compsci 0.3.0.1 → 0.3.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 6b9d3fa913e9dc0f7aa9f8711e9aa231c00d1022
4
- data.tar.gz: 8436157b3364c791cee0471ae74ca3817f0f4dde
2
+ SHA256:
3
+ metadata.gz: b1ad9a59954ea3377e0e03992dd660fabaf7c65389d633f1e607d3a5b6731ebd
4
+ data.tar.gz: 5b893649cae5840c590bf4998429087cf50ad9dc97169a2c3ee1566c86748196
5
5
  SHA512:
6
- metadata.gz: 1670fd7283f147996dea2ed2a7a190797a33a5b22b60e8ccfa98a5dc48d61aa6a43302badbc7776b6b7c5a7171a32923ed2dc95f88c23ca998bd1d023d3f4f72
7
- data.tar.gz: f30dd40fb2e5f9e04db6044d7801f1776fb0e1214fd23c29bfbef028dbcd87cab612e434e4df43da477012975561cb7eeef6dab867a53e479612893c53a9e086
6
+ metadata.gz: 64100e3719380956c844e7f9eb3949eae097a6d9426b039d0d224260d4bd18a1e1dd7ad7f147643203e21b3ba95d0109bed198d8e5421c9e3c6c21312665b426
7
+ data.tar.gz: c8944161d1ee4b4df7afac5d27bc0801b2953893ea45db03c30ec1e9f5ee74764638464ee1c3d4d3707107370dd547eedb1f62d09cfe9f20f2efb399e462258f
data/README.md CHANGED
@@ -1,88 +1,107 @@
1
1
  [![Build Status](https://travis-ci.org/rickhull/compsci.svg?branch=master)](https://travis-ci.org/rickhull/compsci)
2
+ [![Gem Version](https://badge.fury.io/rb/compsci.svg)](https://badge.fury.io/rb/compsci)
3
+ [![Dependency Status](https://gemnasium.com/rickhull/compsci.svg)](https://gemnasium.com/rickhull/compsci)
4
+ [![Security Status](https://hakiri.io/github/rickhull/compsci/master.svg)](https://hakiri.io/github/rickhull/compsci/master)
2
5
 
3
6
  # CompSci
4
7
 
5
8
  Provided are some toy implementations for some basic computer science problems.
6
9
 
7
- ## [`Node`](lib/compsci/node.rb) data structure
10
+ ## [`Node`](lib/compsci/node.rb) classes
11
+
12
+ ### `Node`
13
+
14
+ A *Node* provides a tree structure by assigning other *Nodes* to `@children`.
8
15
 
9
16
  * `Node`
10
17
  - `@value`
11
18
  - `@children`
12
- - `#set_child(idx, node)`
13
- * `KeyNode` inherits from `Node`; adds a key
14
- - `@key`
15
- * `FlexNode` inherits from `Node`; accumulates children
16
- - `#add_child(node)`
17
- - `#new_child(value)`
18
- - `#add_parent(node)`
19
- * `ChildNode` inherits from `Node`; adds a parent
19
+ - `#[]` - child node at index
20
+ - `#[]=` - set child node at index
21
+ - `display` - display full tree with all descendents
22
+
23
+ * [examples/tree.rb](examples/tree.rb)
24
+ * [test/node.rb](test/node.rb#L7)
25
+
26
+ ### `KeyNode`
27
+
28
+ A *KeyNode* adds `@key` and allows a comparison based search on the key.
29
+ [Binary search trees](https://en.wikipedia.org/wiki/Binary_search_tree)
30
+ are supported, and the `@duplicated` flag determines whether duplicate keys
31
+ are allowed to be inserted. Any duplicates will not be returned from
32
+ `#search`. A Ternary search tree is also supported, and it inherently allows
33
+ duplicates keys. `#search` returns an array of `KeyNode`, possibly empty.
34
+
35
+ * `KeyNode < Node`
36
+ - `KeyNode.key_cmp_idx` - compare 2 keys to decide on a child slot
37
+ - `@key` - any *Comparable*
38
+ - `@duplicates` - boolean flag relevant for @children.size == 2
39
+ - `#cidx` - calls `KeyNode.key_cmp_idx`
40
+ - `#insert`
41
+ - `#search`
42
+
43
+ * [examples/binary_search_tree.rb](examples/binary_search_tree.rb)
44
+ * [examples/ternary_search_tree.rb](examples/ternary_search_tree.rb)
45
+ * [test/node.rb](test/node.rb#L43)
46
+
47
+ ### `ChildNode`
48
+
49
+ A *ChildNode* adds reference to its `@parent`.
50
+
51
+ * `ChildNode < Node`
20
52
  - `@parent`
21
53
  - `#gen`
22
54
  - `#siblings`
23
- * `ChildFlexNode` inherits from `ChildNode`; accumulates children
24
- - `#add_child(node)`
25
- - `#new_child(value)`
26
- - `#add_parent(node)`
27
-
28
- ## [`Tree`](lib/compsci/tree.rb) data structures
29
-
30
- * `Tree`
31
- - `@root`
32
- - `#df_search`
33
- - `#bf_search`
34
- * `NaryTree`
35
- - `@child_slots` (number of children per node)
36
- - `#open_parent` O(n) to find a node with open child slots
37
- - `#push` append `#open_parent.children`
38
- - `#display` if initialized with `ChildNode`
39
- * `BinaryTree`
40
- - `NaryTree.new(child_slots: 2)`
41
- - `#display` for `Node` and `ChildNode`
42
- * `TernaryTree`
43
- - `NaryTree.new(child_slots: 3)`
44
- * `QuaternaryTree`
45
- - `NaryTree.new(child_slots: 4)`
46
-
47
- ## [`CompleteNaryTree`](lib/compsci/complete_tree.rb) data structure
48
-
49
- Efficient Array implementation of a complete tree.
50
-
51
- * `CompleteNaryTree`
52
- - `CompleteNaryTree.parent_idx`
53
- - `CompleteNaryTree.children_idx`
54
- - `CompleteNaryTree.gen`
55
+
56
+ * [test/node.rb](test/node.rb#L190)
57
+
58
+ ## [`CompleteTree`](lib/compsci/complete_tree.rb) classes
59
+
60
+ Efficient *Array* implementation of a complete tree uses arithmetic to
61
+ determine parent/child relationships.
62
+
63
+ * `CompleteTree`
64
+ - `CompleteTree.parent_idx`
65
+ - `CompleteTree.children_idx`
66
+ - `CompleteTree.gen`
55
67
  - `@array`
56
68
  - `@child_slots`
57
69
  - `#push`
58
70
  - `#pop`
59
71
  - `#size`
60
72
  - `#last_idx`
61
- - `#display` (alias `#to_s`)
62
- * `CompleteBinaryTree`
63
- - `CompleteNaryTree.new(child_slots: 2)`
64
- * `CompleteTernaryTree`
65
- - `CompleteNaryTree.new(child_slots: 3)`
66
- * `CompleteQuaternaryTree`
67
- - `CompleteNaryTree.new(child_slots: 4)`
68
-
69
- ## [`BinarySearchTree`](lib/compsci/binary_search_tree.rb) data structure
70
-
71
- Based on `BinaryTree` with `KeyNode`s. The position of a node depends on its
72
- key and how the key relates to the existing node keys.
73
-
74
- ## [`Heap`](lib/compsci/heap.rb) data structure
75
-
76
- `CompleteNaryTree` implementation. Both minheaps and maxheaps are supported.
77
- Any number of children may be provided via `child_slots`. The primary
78
- operations are `Heap#push` and `Heap#pop`. See the
79
- [heap](examples/heap.rb) [examples](examples/heap_push.rb)
80
- which can be executed (among other examples) via `rake examples`.
73
+ - `#display` - alias `#to_s`
74
+ * `CompleteBinaryTree < CompleteTree`
75
+ - `@child_slots = 2`
76
+ * `CompleteTernaryTree < CompleteTree`
77
+ - `@child_slots = 3`
78
+ * `CompleteQuaternaryTree < CompleteTree`
79
+ - `@child_slots = 4`
80
+
81
+ * [examples/complete_tree.rb](examples/complete_tree.rb)
82
+ * [test/complete_tree.rb](test/complete_tree.rb)
83
+ * [test/bench/complete_tree.rb](test/bench/complete_tree.rb)
84
+
85
+ ## [`Heap`](lib/compsci/heap.rb) class
86
+
87
+ *CompleteTree* implementation. Both *minheaps* and *maxheaps* are
88
+ supported. Any number of children may be provided via `child_slots`.
89
+ The primary operations are `Heap#push` and `Heap#pop`. My basic Vagrant VM
90
+ gets over [500k pushes per second](reports/examples#L533), constant up past
91
+ 1M pushes.
92
+
93
+ * `Heap < CompleteTree`
94
+ - `#push`
95
+ - `#pop`
96
+ - `#sift_up`
97
+ - `#sift_down`
81
98
 
82
- My basic Vagrant VM gets over [500k pushes per second, constant up past 1M
83
- pushes](reports/examples#L484).
99
+ * [examples/heap.rb](examples/heap.rb)
100
+ * [examples/heap_push.rb](examples/heap_push.rb)
101
+ * [test/heap.rb](test/heap.rb)
102
+ * [test/bench/heap.rb](test/bench/heap.rb)
84
103
 
85
- ## [`Fibonacci`](lib/compsci/fibonacci.rb) functions
104
+ ## [`Fibonacci`](lib/compsci/fibonacci.rb) module
86
105
 
87
106
  * `Fibonacci.classic(n)` - naive, recursive
88
107
  * `Fibonacci.cache_recursive(n)` - as above, caching already computed results
@@ -90,13 +109,22 @@ pushes](reports/examples#L484).
90
109
  * `Fibonacci.dynamic(n)` - as above but without a cache structure
91
110
  * `Fibonacci.matrix(n)` - matrix is magic; beats dynamic around n=500
92
111
 
93
- ## [`Timer`](/lib/compsci/timer.rb) functions
112
+ * [test/fibonacci.rb](test/fibonacci.rb)
113
+ * [test/bench/fibonacci.rb](test/bench/fibonacci.rb)
114
+
115
+ ## [`Timer`](/lib/compsci/timer.rb) module
94
116
 
95
117
  * `Timer.now` - uses `Process::CLOCK_MONOTONIC` if available
96
118
  * `Timer.since` - provides the elapsed time since a prior time
97
119
  * `Timer.elapsed` - provides the elapsed time to run a block
98
120
  * `Timer.loop_avg` - loops a block; returns final value and mean elapsed time
99
121
 
122
+ * [examples/heap_push.rb](examples/heap_push.rb)
123
+ * [test/timer.rb](test/timer.rb)
124
+ * [test/bench/complete_tree.rb](test/bench/complete_tree.rb)
125
+ * [test/bench/simplex.rb](test/bench/simplex.rb)
126
+ * [test/timer.rb](test/timer.rb)
127
+
100
128
  ```ruby
101
129
  require 'compsci/timer'
102
130
 
@@ -142,36 +170,67 @@ elapsed: 0.304
142
170
  cumulative: 0.828
143
171
  ```
144
172
 
145
- ## [`Fit`](lib/compsci/fit.rb) functions
173
+ ## [`Fit`](lib/compsci/fit.rb) module
146
174
 
147
175
  * `Fit.sigma` - sums the result of a block applied to array values
148
176
  * `Fit.error` - returns a generic r^2 value, the coefficient of determination
149
- * `Fit.constant` - fits `y = a + 0x`; returns the mean and variance
177
+ * `Fit.constant` - fits `y = a + 0x`; returns the mean and variance
150
178
  * `Fit.logarithmic` - fits `y = a + b*ln(x)`; returns a, b, r^2
151
- * `Fit.linear` - fits `y = a + bx`; returns a, b, r^2
152
- * `Fit.exponential` fits `y = ae^(bx)`; returns a, b, r^2
153
- * `Fit.power` fits `y = ax^b`; returns a, b, r^2
179
+ * `Fit.linear` - fits `y = a + bx`; returns a, b, r^2
180
+ * `Fit.exponential` - fits `y = ae^(bx)`; returns a, b, r^2
181
+ * `Fit.power` - fits `y = ax^b`; returns a, b, r^2
182
+ * `Fit.best` - applies known fits; returns the fit with highest r^2
183
+
184
+ * [test/bench/complete_tree.rb](test/bench/complete_tree.rb)
185
+ * [test/fit.rb](test/fit.rb)
186
+
187
+ ## [`Names`](lib/compsci/names.rb) module
154
188
 
155
- ## [`Names`](lib/compsci/names.rb) functions
189
+ This helps map a range of small integers to friendly names, typically in
190
+ alphabetical order.
156
191
 
192
+ * `ENGLISH_UPPER` `ENGLISH_LOWER` `WW1` `WW2` `NATO` `CRYPTO` `PLANETS` `SOLAR`
157
193
  * `Names.assign`
158
- * `Names::Greek.upper`
159
- * `Names::Greek.lower`
160
- * `Names::Greek.symbol`
194
+
195
+ * [examples/binary_search_tree.rb](examples/binary_search_tree.rb)
196
+ * [examples/ternary_search_tree.rb](examples/ternary_search_tree.rb)
197
+ * [test/names.rb](test/names.rb)
198
+ * [test/node.rb](test/node.rb)
199
+
200
+ ### [`Names::Greek`](lib/compsci/names/greek.rb) module
201
+
202
+ - `UPPER` `LOWER` `SYMBOLS` `CHAR_MAP` `LATIN_SYMBOLS` `SYMBOLS26`
203
+ - `Names::Greek.upper`
204
+ - `Names::Greek.lower`
205
+ - `Names::Greek.sym`
206
+
207
+ ### [`Names::Pokemon`](lib/compsci/names/pokemon.rb) module
208
+
209
+ - `Names::Pokemon.array`
210
+ - `Names::Pokemon.hash`
211
+ - `Names::Pokemon.grep`
212
+ - `Names::Pokemon.sample`
161
213
 
162
214
  ## [`Simplex`](lib/compsci/simplex.rb) class
163
215
 
164
- The Simplex algorithm is a technique for Linear Programming. Typically the
165
- problem is to maximize some linear expression of variables given some
166
- constraints on those variables given in terms of linear inequalities.
216
+ The [Simplex algorithm](https://en.wikipedia.org/wiki/Simplex_algorithm)
217
+ is a technique for
218
+ [Linear programming](https://en.wikipedia.org/wiki/Linear_programming).
219
+ Typically the problem is to maximize some linear expression of variables
220
+ given some constraints on those variables in terms of linear inequalities.
221
+
222
+ * [test/bench/simplex.rb](test/bench/simplex.rb)
223
+ * [test/simplex.rb](test/simplex.rb)
167
224
 
168
- ### [`Simplex::Parse`](lib/compsci/simplex/parse.rb) functions
225
+ ### [`Simplex::Parse`](lib/compsci/simplex/parse.rb) module
169
226
 
170
227
  * `Parse.tokenize` - convert a string to an array of tokens
171
228
  * `Parse.term` - parse certain tokens into [coefficient, varname]
172
229
  * `Parse.expression` - parse a string representing a sum of terms
173
230
  * `Parse.inequality` - parse a string like "#{expression} <= #{const}"
174
231
 
232
+ * [test/simplex_parse.rb](test/simplex_parse.rb)
233
+
175
234
  With `Simplex::Parse`, one can obtain solutions via:
176
235
 
177
236
  * `Simplex.maximize` - takes an expression to maximize followed by a variable
data/Rakefile CHANGED
@@ -78,7 +78,9 @@ scripts = [
78
78
  "examples/heap.rb",
79
79
  "examples/heap_push.rb",
80
80
  "examples/tree.rb",
81
- "examples/tree_push.rb",
81
+ "examples/flex_node.rb",
82
+ "examples/binary_search_tree.rb",
83
+ "examples/ternary_search_tree.rb",
82
84
  ]
83
85
 
84
86
  desc "Run ruby-prof on examples/"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0.1
1
+ 0.3.1.1
@@ -16,8 +16,8 @@ Gem::Specification.new do |s|
16
16
  s.files += Dir['examples/**/*.rb']
17
17
 
18
18
  s.add_development_dependency "buildar", "~> 3.0"
19
- s.add_development_dependency "minitest", "~> 5.0"
20
- s.add_development_dependency "rake", "~> 0"
19
+ s.add_development_dependency "minitest", ">= 5.0"
20
+ s.add_development_dependency "rake", ">= 12.3.3" # CVE-2020-8130
21
21
  s.add_development_dependency "flog", "~> 0"
22
22
  s.add_development_dependency "flay", "~> 0"
23
23
  s.add_development_dependency "roodi", "~> 0"
@@ -1,16 +1,51 @@
1
1
  require 'compsci/node'
2
- require 'compsci/binary_search_tree'
3
2
  require 'compsci/names'
4
3
 
5
4
  include CompSci
6
5
 
7
- RANDMAX = 99
6
+ puts <<EOF
7
+
8
+ #
9
+ # Insert nodes into a BST (random keys, duplicates: true)
10
+ #
11
+
12
+ EOF
13
+
14
+ randmax = 99
8
15
 
9
16
  p vals = Names::WW1.shuffle
10
- p keys = Array.new(vals.size) { rand RANDMAX }
17
+ p keys = Array.new(vals.size) { rand randmax }
18
+
19
+ root = KeyNode.new(vals.shift, key: keys.shift, children: 2, duplicates: true)
20
+ root.insert(keys.shift, vals.shift) until keys.empty?
21
+
22
+ puts root.display
23
+ puts
24
+
25
+ puts <<EOF
26
+
27
+ #
28
+ # Insert 30 nodes into a BST (unique keys, duplicates: false)
29
+ #
30
+
31
+ EOF
32
+
33
+ keys = (1..30).to_a.shuffle
34
+ vals = keys.map { rand 99 }
35
+
36
+ root = KeyNode.new(vals.shift, key: keys.shift, children: 2)
37
+ root.insert(keys.shift, vals.shift) while !keys.empty?
38
+ puts root.display
39
+
40
+ puts <<EOF
41
+
42
+ #
43
+ # Search for 30 different keys
44
+ #
45
+
46
+ EOF
11
47
 
12
- root = BinarySearchTree.new_node(keys.shift, vals.shift)
13
- tree = BinarySearchTree.new(root)
14
- tree[keys.shift] = vals.shift until keys.empty?
15
- # tree.insert(keys.shift, vals.shift) until keys.empty?
16
- puts tree
48
+ (1..30).each { |key|
49
+ node = root.search(key)
50
+ puts "found #{node}"
51
+ }
@@ -1,47 +1,46 @@
1
1
  require 'compsci/complete_tree'
2
- require 'compsci/timer'
3
2
 
4
3
  include CompSci
5
4
 
6
- puts <<EOF
5
+ vals = Array.new(30) { rand 99 }
6
+
7
+ [CompleteBinaryTree,
8
+ CompleteTernaryTree,
9
+ CompleteQuaternaryTree].each { |tree_class|
10
+
11
+ puts <<EOF
12
+
7
13
  #
8
- # Print CompleteBinary-, Ternary-, and QuaternaryTree
14
+ # Print #{tree_class} filled with static vals
9
15
  #
10
16
 
11
17
  EOF
12
18
 
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
19
  my_vals = vals.dup
21
- p my_vals
20
+ puts "initial vals: #{my_vals.inspect}"
22
21
  tree = tree_class.new
23
22
  tree.push my_vals.shift until my_vals.empty?
23
+
24
24
  p tree
25
- puts tree.display(width: 80)
26
- puts
27
25
  puts
26
+ puts tree.display(width: 80)
28
27
  puts
29
28
 
30
29
 
31
- # TODO: add CompleteTree#df_search
32
- # tree.df_search { |n|
33
- # puts "visited #{n}"
34
- # false # or n.value > 90
35
- # }
36
- # puts
30
+ puts <<EOF
31
+
32
+ #
33
+ # Push random vals and print again
34
+ #
35
+
36
+ EOF
37
37
 
38
- # push different vals for each class
39
38
  my_vals = Array.new(30) { rand 99 }
40
- puts "push: #{my_vals.inspect}"
39
+ puts "new vals: #{my_vals.inspect}"
41
40
 
42
41
  tree.push my_vals.shift until my_vals.empty?
43
- puts tree.display(width: 80)
44
42
  puts
43
+ puts tree.display(width: 80)
45
44
  puts
46
45
  puts
47
46
  }
@@ -0,0 +1,117 @@
1
+ require 'compsci/flex_node'
2
+ require 'compsci/timer'
3
+
4
+ include CompSci
5
+
6
+ puts <<EOF
7
+
8
+ #
9
+ # Try out Binary, Ternary, and Quaternary FlexNodes
10
+ # Push the same vals to each
11
+ #
12
+
13
+ EOF
14
+
15
+ vals = Array.new(30) { rand 99 }
16
+
17
+ [2, 3, 4].each { |child_slots|
18
+ my_vals = vals.dup
19
+ p my_vals
20
+
21
+ root = ChildFlexNode.new my_vals.shift
22
+ root.push(my_vals.shift, child_slots) until my_vals.empty?
23
+ p root
24
+ puts root.display(width: 80)
25
+ puts
26
+ visited = []
27
+ root.df_search { |n|
28
+ visited << n
29
+ false # or n.value > 90
30
+ }
31
+ puts "df_search visited: %s" % visited.join(' ')
32
+ puts
33
+ puts
34
+
35
+ # push different vals for each class
36
+ my_vals = Array.new(30) { rand 99 }
37
+ puts "push: #{my_vals.inspect}"
38
+ root.push(my_vals.shift, child_slots) until my_vals.empty?
39
+ puts
40
+ puts root.display(width: 80)
41
+ puts
42
+ puts
43
+ }
44
+
45
+ puts <<EOF
46
+
47
+ #
48
+ # 30 ChildFlexNode pushes and df_search
49
+ #
50
+
51
+ EOF
52
+
53
+ vals = Array.new(30) { rand 99 }
54
+ p vals
55
+
56
+ root = ChildFlexNode.new vals.shift
57
+ child_slots = 2
58
+ root.push(vals.shift, child_slots) until vals.empty?
59
+ p root
60
+ puts root.display
61
+ puts
62
+
63
+ root.df_search { |n|
64
+ puts "visited #{n}"
65
+ false # or n.value > 90
66
+ }
67
+ puts
68
+
69
+ vals = Array.new(30) { rand 99 }
70
+ puts "push: #{vals.inspect}"
71
+
72
+ root.push(vals.shift, child_slots) until vals.empty?
73
+ puts root.display
74
+ puts
75
+
76
+
77
+ runtime = (ARGV.shift || "3").to_i
78
+ puts <<EOF
79
+
80
+ #
81
+ # #{runtime} seconds worth of Binary ChildFlexNode pushes
82
+ #
83
+
84
+ EOF
85
+
86
+ count = 0
87
+ start = Timer.now
88
+ start_1k = Timer.now
89
+ root = ChildFlexNode.new(rand 99)
90
+ child_slots = 2
91
+
92
+ loop {
93
+ count += 1
94
+
95
+ if count % 100 == 0
96
+ _ans, push_elapsed = Timer.elapsed {
97
+ root.push(rand(99), child_slots)
98
+ }
99
+ puts "%ith push: %0.8f s" % [count, push_elapsed]
100
+
101
+ if count % 1000 == 0
102
+ push_1k_elapsed = Timer.since start_1k
103
+ puts "-----------"
104
+ puts " 1k push: %0.4f s (%i push / s)" %
105
+ [push_1k_elapsed, 1000.to_f / push_1k_elapsed]
106
+ puts
107
+ start_1k = Timer.now
108
+ end
109
+ else
110
+ root.push(rand(99), child_slots)
111
+ end
112
+
113
+ break if Timer.since(start) > runtime
114
+ }
115
+
116
+ puts "pushed %i items in %0.1f s" % [count, Timer.since(start)]
117
+ puts