compsci 0.1.1.1 → 0.2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +74 -5
- data/Rakefile +20 -9
- data/VERSION +1 -1
- data/compsci.gemspec +1 -0
- data/examples/binary_search_tree.rb +16 -0
- data/examples/heap.rb +0 -42
- data/examples/heap_push.rb +46 -0
- data/examples/tree.rb +2 -1
- data/examples/{binary_tree.rb → tree_push.rb} +3 -2
- data/lib/compsci/binary_search_tree.rb +86 -0
- data/lib/compsci/fibonacci.rb +1 -9
- data/lib/compsci/fit.rb +34 -14
- data/lib/compsci/names.rb +3 -4
- data/lib/compsci/node.rb +66 -19
- data/lib/compsci/simplex.rb +173 -0
- data/lib/compsci/simplex/parse.rb +125 -0
- data/lib/compsci/tree.rb +14 -1
- data/test/bench/complete_tree.rb +59 -0
- data/test/bench/fibonacci.rb +0 -4
- data/test/bench/simplex.rb +141 -0
- data/test/bench/tree.rb +20 -15
- data/test/binary_search_tree.rb +106 -0
- data/test/fit.rb +5 -11
- data/test/node.rb +55 -4
- data/test/simplex.rb +291 -0
- data/test/simplex_parse.rb +94 -0
- data/test/tree.rb +33 -9
- metadata +27 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fa74f40bbc97fa685c811d2b15738da31d69c66
|
4
|
+
data.tar.gz: '02965023a412fae230e7fe3e42704982c6410bab'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4832093f2d37d27b55f2b32fe20422704100d7cd515d51790d745dbf22d7006866959dc844939d2cff19e60d3ee54b78100a9785511274ed43aa22dd86a7fd8
|
7
|
+
data.tar.gz: 5b5ad3eeedadddd92abca745bf7822dbd9cff07fa79ccc6d34cae075d6a1c24dbc747aa1939d44806e1ad83b914b9e0b880fc6be26c505c98f869fa3dd1ff9f6
|
data/README.md
CHANGED
@@ -9,10 +9,21 @@ Provided are some toy implementations for some basic computer science problems.
|
|
9
9
|
* `Node`
|
10
10
|
- `@value`
|
11
11
|
- `@children`
|
12
|
-
|
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
|
13
20
|
- `@parent`
|
14
21
|
- `#gen`
|
15
22
|
- `#siblings`
|
23
|
+
* `ChildFlexNode` inherits from `ChildNode`; accumulates children
|
24
|
+
- `#add_child(node)`
|
25
|
+
- `#new_child(value)`
|
26
|
+
- `#add_parent(node)`
|
16
27
|
|
17
28
|
## [`Tree`](lib/compsci/tree.rb) data structures
|
18
29
|
|
@@ -55,16 +66,21 @@ Efficient Array implementation of a complete tree.
|
|
55
66
|
* `CompleteQuaternaryTree`
|
56
67
|
- `CompleteNaryTree.new(child_slots: 4)`
|
57
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
|
+
|
58
74
|
## [`Heap`](lib/compsci/heap.rb) data structure
|
59
75
|
|
60
76
|
`CompleteNaryTree` implementation. Both minheaps and maxheaps are supported.
|
61
77
|
Any number of children may be provided via `child_slots`. The primary
|
62
78
|
operations are `Heap#push` and `Heap#pop`. See the
|
63
|
-
[heap
|
64
|
-
via `rake examples`.
|
79
|
+
[heap](examples/heap.rb) [examples](examples/heap_push.rb)
|
80
|
+
which can be executed (among other examples) via `rake examples`.
|
65
81
|
|
66
|
-
My basic Vagrant VM gets
|
67
|
-
pushes.
|
82
|
+
My basic Vagrant VM gets over [500k pushes per second, constant up past 1M
|
83
|
+
pushes](reports/examples#L484).
|
68
84
|
|
69
85
|
## [`Fibonacci`](lib/compsci/fibonacci.rb) functions
|
70
86
|
|
@@ -142,3 +158,56 @@ cumulative: 0.828
|
|
142
158
|
* `Names::Greek.upper`
|
143
159
|
* `Names::Greek.lower`
|
144
160
|
* `Names::Greek.symbol`
|
161
|
+
|
162
|
+
## [`Simplex`](lib/compsci/simplex.rb) class
|
163
|
+
|
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.
|
167
|
+
|
168
|
+
### [`Simplex::Parse`](lib/compsci/simplex/parse.rb) functions
|
169
|
+
|
170
|
+
* `Parse.tokenize` - convert a string to an array of tokens
|
171
|
+
* `Parse.term` - parse certain tokens into [coefficient, varname]
|
172
|
+
* `Parse.expression` - parse a string representing a sum of terms
|
173
|
+
* `Parse.inequality` - parse a string like "#{expression} <= #{const}"
|
174
|
+
|
175
|
+
With `Simplex::Parse`, one can obtain solutions via:
|
176
|
+
|
177
|
+
* `Simplex.maximize` - takes an expression to maximize followed by a variable
|
178
|
+
number of constraints / inequalities; returns a solution
|
179
|
+
* `Simplex.problem` - a more general form of `Simplex.maximize`; returns a
|
180
|
+
Simplex object
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
require 'compsci/simplex/parse'
|
184
|
+
|
185
|
+
include CompSci
|
186
|
+
|
187
|
+
Simplex.maximize('x + y',
|
188
|
+
'2x + y <= 4',
|
189
|
+
'x + 2y <= 3')
|
190
|
+
|
191
|
+
# => [1.6666666666666667, 0.6666666666666666]
|
192
|
+
|
193
|
+
|
194
|
+
|
195
|
+
s = Simplex.problem(maximize: 'x + y',
|
196
|
+
constraints: ['2x + y <= 4',
|
197
|
+
'x + 2y <= 3'])
|
198
|
+
|
199
|
+
# => #<CompSci::Simplex:0x0055b2deadbeef
|
200
|
+
# @max_pivots=10000,
|
201
|
+
# @num_non_slack_vars=2,
|
202
|
+
# @num_constraints=2,
|
203
|
+
# @num_vars=4,
|
204
|
+
# @c=[-1.0, -1.0, 0, 0],
|
205
|
+
# @a=[[2.0, 1.0, 1, 0], [1.0, 2.0, 0, 1]],
|
206
|
+
# @b=[4.0, 3.0],
|
207
|
+
# @basic_vars=[2, 3],
|
208
|
+
# @x=[0, 0, 4.0, 3.0]>
|
209
|
+
|
210
|
+
s.solution
|
211
|
+
|
212
|
+
# => [1.6666666666666667, 0.6666666666666666]
|
213
|
+
```
|
data/Rakefile
CHANGED
@@ -22,20 +22,18 @@ end
|
|
22
22
|
|
23
23
|
task default: :examples
|
24
24
|
|
25
|
+
|
25
26
|
#
|
26
27
|
# METRICS
|
27
28
|
#
|
28
29
|
|
29
|
-
metrics_tasks = []
|
30
|
-
|
31
30
|
begin
|
32
31
|
require 'flog_task'
|
33
32
|
FlogTask.new do |t|
|
34
|
-
t.threshold =
|
33
|
+
t.threshold = 9000
|
35
34
|
t.dirs = ['lib']
|
36
35
|
t.verbose = true
|
37
36
|
end
|
38
|
-
metrics_tasks << :flog
|
39
37
|
rescue LoadError
|
40
38
|
warn 'flog_task unavailable'
|
41
39
|
end
|
@@ -46,7 +44,6 @@ begin
|
|
46
44
|
t.dirs = ['lib']
|
47
45
|
t.verbose = true
|
48
46
|
end
|
49
|
-
metrics_tasks << :flay
|
50
47
|
rescue LoadError
|
51
48
|
warn 'flay_task unavailable'
|
52
49
|
end
|
@@ -54,13 +51,10 @@ end
|
|
54
51
|
begin
|
55
52
|
require 'roodi_task'
|
56
53
|
RoodiTask.new config: '.roodi.yml', patterns: ['lib/**/*.rb']
|
57
|
-
metrics_tasks << :roodi
|
58
54
|
rescue LoadError
|
59
55
|
warn "roodi_task unavailable"
|
60
56
|
end
|
61
57
|
|
62
|
-
desc "Generate code metrics reports"
|
63
|
-
task code_metrics: metrics_tasks
|
64
58
|
|
65
59
|
#
|
66
60
|
# PROFILING
|
@@ -80,10 +74,11 @@ def rprof_sh(script, args = '', rprof_args = '')
|
|
80
74
|
end
|
81
75
|
|
82
76
|
scripts = [
|
83
|
-
"examples/binary_tree.rb",
|
84
77
|
"examples/complete_tree.rb",
|
85
78
|
"examples/heap.rb",
|
79
|
+
"examples/heap_push.rb",
|
86
80
|
"examples/tree.rb",
|
81
|
+
"examples/tree_push.rb",
|
87
82
|
]
|
88
83
|
|
89
84
|
desc "Run ruby-prof on examples/"
|
@@ -96,6 +91,22 @@ task "ruby-prof-exclude" => "loadavg" do
|
|
96
91
|
scripts.each { |script| rprof_sh script, "", "--exclude-common-cycles" }
|
97
92
|
end
|
98
93
|
|
94
|
+
|
95
|
+
#
|
96
|
+
# REPORTS
|
97
|
+
#
|
98
|
+
|
99
|
+
|
100
|
+
desc "Generate code metrics and reports"
|
101
|
+
task report: :test do
|
102
|
+
%w{examples bench flog flay roodi ruby-prof ruby-prof-exclude}.each { |t|
|
103
|
+
sh "rake #{t} > reports/#{t} 2>&1" do |ok, _status|
|
104
|
+
puts "rake #{t} failed" unless ok
|
105
|
+
end
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
|
99
110
|
#
|
100
111
|
# GEM BUILD / PUBLISH
|
101
112
|
#
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0.1
|
data/compsci.gemspec
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'compsci/node'
|
2
|
+
require 'compsci/binary_search_tree'
|
3
|
+
require 'compsci/names'
|
4
|
+
|
5
|
+
include CompSci
|
6
|
+
|
7
|
+
RANDMAX = 99
|
8
|
+
|
9
|
+
p vals = Names::WW1.shuffle
|
10
|
+
p keys = Array.new(vals.size) { rand RANDMAX }
|
11
|
+
|
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
|
data/examples/heap.rb
CHANGED
@@ -3,48 +3,6 @@ require 'compsci/timer'
|
|
3
3
|
|
4
4
|
include CompSci
|
5
5
|
|
6
|
-
puts <<EOF
|
7
|
-
#
|
8
|
-
# 3 seconds worth of pushes
|
9
|
-
#
|
10
|
-
|
11
|
-
EOF
|
12
|
-
|
13
|
-
count = 0
|
14
|
-
start = Timer.now
|
15
|
-
start_100k = Timer.now
|
16
|
-
h = Heap.new
|
17
|
-
|
18
|
-
loop {
|
19
|
-
count += 1
|
20
|
-
|
21
|
-
if count % 10000 == 0
|
22
|
-
_answer, push_elapsed = Timer.elapsed { h.push rand 99999 }
|
23
|
-
puts "%ith push: %0.8f s" % [count, push_elapsed]
|
24
|
-
if count % 100000 == 0
|
25
|
-
h.push rand 99999
|
26
|
-
push_100k_elapsed = Timer.since start_100k
|
27
|
-
puts "-------------"
|
28
|
-
puts " 100k push: %0.8f s (%ik push / s)" %
|
29
|
-
[push_100k_elapsed, 100.to_f / push_100k_elapsed]
|
30
|
-
puts
|
31
|
-
start_100k = Timer.now
|
32
|
-
end
|
33
|
-
else
|
34
|
-
h.push rand 99999
|
35
|
-
end
|
36
|
-
|
37
|
-
break if Timer.since(start) > 3
|
38
|
-
}
|
39
|
-
|
40
|
-
puts "pushed %i items in %0.1f s" % [count, Timer.since(start)]
|
41
|
-
puts
|
42
|
-
|
43
|
-
print "still a heap with #{h.size} items? "
|
44
|
-
answer, elapsed = Timer.elapsed { h.heap? }
|
45
|
-
puts "%s - %0.3f sec" % [answer ? 'YES' : 'NO', elapsed]
|
46
|
-
puts
|
47
|
-
|
48
6
|
puts <<EOF
|
49
7
|
#
|
50
8
|
# display the results of TernaryHeap push and pop
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'compsci/heap'
|
2
|
+
require 'compsci/timer'
|
3
|
+
|
4
|
+
include CompSci
|
5
|
+
|
6
|
+
puts <<EOF
|
7
|
+
#
|
8
|
+
# 3 seconds worth of pushes
|
9
|
+
#
|
10
|
+
|
11
|
+
EOF
|
12
|
+
|
13
|
+
count = 0
|
14
|
+
start = Timer.now
|
15
|
+
start_100k = Timer.now
|
16
|
+
h = Heap.new
|
17
|
+
|
18
|
+
loop {
|
19
|
+
count += 1
|
20
|
+
|
21
|
+
if count % 10000 == 0
|
22
|
+
_answer, push_elapsed = Timer.elapsed { h.push rand 99999 }
|
23
|
+
puts "%ith push: %0.8f s" % [count, push_elapsed]
|
24
|
+
if count % 100000 == 0
|
25
|
+
h.push rand 99999
|
26
|
+
push_100k_elapsed = Timer.since start_100k
|
27
|
+
puts "-------------"
|
28
|
+
puts " 100k push: %0.8f s (%ik push / s)" %
|
29
|
+
[push_100k_elapsed, 100.to_f / push_100k_elapsed]
|
30
|
+
puts
|
31
|
+
start_100k = Timer.now
|
32
|
+
end
|
33
|
+
else
|
34
|
+
h.push rand 99999
|
35
|
+
end
|
36
|
+
|
37
|
+
break if Timer.since(start) > 3
|
38
|
+
}
|
39
|
+
|
40
|
+
puts "pushed %i items in %0.1f s" % [count, Timer.since(start)]
|
41
|
+
puts
|
42
|
+
|
43
|
+
print "still a heap with #{h.size} items? "
|
44
|
+
answer, elapsed = Timer.elapsed { h.heap? }
|
45
|
+
puts "%s - %0.3f sec" % [answer ? 'YES' : 'NO', elapsed]
|
46
|
+
puts
|
data/examples/tree.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'compsci/node'
|
1
2
|
require 'compsci/tree'
|
2
3
|
require 'compsci/timer'
|
3
4
|
|
@@ -16,7 +17,7 @@ vals = Array.new(30) { rand 99 }
|
|
16
17
|
# start with the same vals for each class
|
17
18
|
my_vals = vals.dup
|
18
19
|
p my_vals
|
19
|
-
tree = tree_class.new(
|
20
|
+
tree = tree_class.new(ChildFlexNode, my_vals.shift)
|
20
21
|
tree.push my_vals.shift until my_vals.empty?
|
21
22
|
p tree
|
22
23
|
puts tree.display(width: 80)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'compsci/node'
|
1
2
|
require 'compsci/tree'
|
2
3
|
require 'compsci/timer'
|
3
4
|
|
@@ -13,7 +14,7 @@ EOF
|
|
13
14
|
count = 0
|
14
15
|
start = Timer.now
|
15
16
|
start_1k = Timer.now
|
16
|
-
tree = BinaryTree.new
|
17
|
+
tree = BinaryTree.new ChildFlexNode, rand(99)
|
17
18
|
|
18
19
|
loop {
|
19
20
|
count += 1
|
@@ -50,7 +51,7 @@ EOF
|
|
50
51
|
vals = Array.new(30) { rand 99 }
|
51
52
|
p vals
|
52
53
|
|
53
|
-
tree = BinaryTree.new
|
54
|
+
tree = BinaryTree.new ChildFlexNode, vals.shift
|
54
55
|
tree.push vals.shift until vals.empty?
|
55
56
|
puts tree
|
56
57
|
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'compsci/node'
|
2
|
+
require 'compsci/tree'
|
3
|
+
|
4
|
+
module CompSci
|
5
|
+
class BinarySearchTree < BinaryTree
|
6
|
+
def self.display_level(nodes: [], width: 80)
|
7
|
+
unless self.power_of?(nodes.size, 2)
|
8
|
+
raise "unexpected node count: #{nodes.size}"
|
9
|
+
end
|
10
|
+
block_width = [width / nodes.size, 1].max
|
11
|
+
nodes.map { |node|
|
12
|
+
str = node ? node.to_s : '_'
|
13
|
+
space = [(block_width + str.size) / 2, str.size + 1].max
|
14
|
+
str.ljust(space, ' ').rjust(block_width, ' ')
|
15
|
+
}.join
|
16
|
+
end
|
17
|
+
|
18
|
+
# helper method; any object which responds to key, value, and children
|
19
|
+
# may be used
|
20
|
+
def self.new_node(key, val)
|
21
|
+
CompSci::KeyNode.new(val, key: key, children: 2)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.new_with_kv(key, val)
|
25
|
+
self.new(self.new_node(key, val))
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(root_node)
|
29
|
+
@node_class = root_node.class
|
30
|
+
@child_slots = 2
|
31
|
+
if root_node.children.size == @child_slots
|
32
|
+
@root = root_node
|
33
|
+
else
|
34
|
+
raise "bad root: #{root_node}; expected #{@child_slots} child slots"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def search_recursive(key, node: @root)
|
39
|
+
return node if node.nil? or node.key == key
|
40
|
+
child = key < node.key ? node.children[0] : node.children[1]
|
41
|
+
search_recursive(key, node: child)
|
42
|
+
end
|
43
|
+
|
44
|
+
def search_iterative(key, node: @root)
|
45
|
+
while !node.nil?
|
46
|
+
return node if node.key == key
|
47
|
+
node = key < node.key ? node.children[0] : node.children[1]
|
48
|
+
end
|
49
|
+
node
|
50
|
+
end
|
51
|
+
|
52
|
+
def insert_recursive(key, val, node: @root)
|
53
|
+
return nil if node.nil? or node.key == key
|
54
|
+
if key < node.key
|
55
|
+
if node.children[0]
|
56
|
+
insert_recursive(key, val, node: node.children[0])
|
57
|
+
else
|
58
|
+
node.children[0] = @node_class.new(val, key: key, children: 2)
|
59
|
+
end
|
60
|
+
else
|
61
|
+
if node.children[1]
|
62
|
+
insert_recursive(key, val, node: node.children[1])
|
63
|
+
else
|
64
|
+
node.children[1] = @node_class.new(val, key: key, children: 2)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
alias_method :insert, :insert_recursive
|
69
|
+
alias_method :[]=, :insert
|
70
|
+
|
71
|
+
def display(node: @root, width: 80)
|
72
|
+
levels = [self.class.display_level(nodes: [node], width: width)]
|
73
|
+
nodes = node.children
|
74
|
+
while nodes.any? { |n| !n.nil? }
|
75
|
+
levels << self.class.display_level(nodes: nodes, width: width)
|
76
|
+
children = []
|
77
|
+
nodes.each { |n|
|
78
|
+
children += n ? n.children : Array.new(@child_slots)
|
79
|
+
}
|
80
|
+
nodes = children
|
81
|
+
end
|
82
|
+
levels.join("\n")
|
83
|
+
end
|
84
|
+
alias_method :to_s, :display
|
85
|
+
end
|
86
|
+
end
|
data/lib/compsci/fibonacci.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
autoload :Matrix, 'matrix'
|
2
2
|
|
3
3
|
module CompSci
|
4
|
-
|
4
|
+
module Fibonacci
|
5
5
|
def self.classic(n)
|
6
6
|
n < 2 ? n : classic(n-1) + classic(n-2)
|
7
7
|
end
|
@@ -17,20 +17,12 @@ module CompSci
|
|
17
17
|
cache[n]
|
18
18
|
end
|
19
19
|
|
20
|
-
# traditional
|
21
20
|
def self.dynamic(n)
|
22
21
|
a, b = 0, 1
|
23
22
|
n.times { a, b = b, a+b }
|
24
23
|
a
|
25
24
|
end
|
26
25
|
|
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
|
-
|
34
26
|
# https://gist.github.com/havenwood/02cf291b809327d96a3f
|
35
27
|
# slower than dynamic until around n == 500
|
36
28
|
def self.matrix(n)
|