rubylabs 0.5.4

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.
Files changed (58) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +9 -0
  3. data/Rakefile +63 -0
  4. data/VERSION +1 -0
  5. data/bin/bb.rb +12 -0
  6. data/bin/statistics2-0.53/ext/extconf.rb +11 -0
  7. data/bin/statistics2-0.53/ext/show.rb +11 -0
  8. data/bin/statistics2-0.53/ext/t.rb +46 -0
  9. data/bin/statistics2-0.53/mklist.rb +26 -0
  10. data/bin/statistics2-0.53/sample-tbl.rb +129 -0
  11. data/bin/statistics2-0.53/statistics2.rb +532 -0
  12. data/bin/statistics2-0.53/t-inv.rb +54 -0
  13. data/bin/statistics2.rb +532 -0
  14. data/data/aafreq.txt +20 -0
  15. data/data/cars.txt +50 -0
  16. data/data/century.txt +1 -0
  17. data/data/colors.txt +64 -0
  18. data/data/earth.yaml +15 -0
  19. data/data/fruit.txt +45 -0
  20. data/data/hacodes.txt +35 -0
  21. data/data/hafreq.txt +16 -0
  22. data/data/hvfreq.txt +5 -0
  23. data/data/nbody.R +23 -0
  24. data/data/nbody.out +731 -0
  25. data/data/nbody.pdf +3111 -0
  26. data/data/nbody.png +0 -0
  27. data/data/nbody3d.pdf +3201 -0
  28. data/data/outer.pdf +182785 -0
  29. data/data/solar.dat +36501 -0
  30. data/data/solarsystem.txt +17 -0
  31. data/data/suits.txt +1 -0
  32. data/data/wordlist.txt +210653 -0
  33. data/lib/bitlab.rb +624 -0
  34. data/lib/elizalab.rb +523 -0
  35. data/lib/encryptionlab.rb +42 -0
  36. data/lib/hashlab.rb +224 -0
  37. data/lib/introlab.rb +14 -0
  38. data/lib/iterationlab.rb +130 -0
  39. data/lib/randomlab.rb +294 -0
  40. data/lib/recursionlab.rb +228 -0
  41. data/lib/rubylabs.rb +507 -0
  42. data/lib/sievelab.rb +58 -0
  43. data/lib/sortlab.rb +213 -0
  44. data/lib/spherelab.rb +352 -0
  45. data/lib/temps.rb +41 -0
  46. data/lib/tsplab.rb +416 -0
  47. data/lib/viewer.rb +65 -0
  48. data/test/bit_test.rb +175 -0
  49. data/test/encryption_test.rb +20 -0
  50. data/test/iteration_test.rb +40 -0
  51. data/test/random_test.rb +64 -0
  52. data/test/recursion_test.rb +47 -0
  53. data/test/rubylabs_test.rb +18 -0
  54. data/test/sieve_test.rb +28 -0
  55. data/test/sphere_test.rb +130 -0
  56. data/test/temps_test.rb +24 -0
  57. data/test/test_helper.rb +18 -0
  58. metadata +112 -0
data/lib/hashlab.rb ADDED
@@ -0,0 +1,224 @@
1
+ =begin rdoc
2
+
3
+ == HashLab
4
+
5
+ Methods used in experiments on hash tables.
6
+
7
+ <b>NOTE:</b> the +insert+ and +find+ methods defined here are "stubs" used to test the hash
8
+ functions. Load the file <tt>hashmethods.rb</tt> to overwrite the stubs with the actual
9
+ methods that create and search buckets.
10
+
11
+ =end
12
+
13
+ module RubyLabs
14
+
15
+ module HashLab
16
+
17
+ =begin rdoc
18
+
19
+ Ruby version of the ``card catalog box'' number, a trivial hash function that
20
+ maps two-letter strings to numbers between 0 and 675.
21
+
22
+ =end
23
+
24
+ # :begin :ccb
25
+ def ccb(s)
26
+ return s[0].ord * 26 + s[1].ord
27
+ end
28
+ # :end :ccb
29
+
30
+ =begin rdoc
31
+
32
+ The "small card catalog box" number, a version of ccb that works
33
+ for a smaller catalog (n = 100 boxes).
34
+
35
+ =end
36
+
37
+ # :begin :sccb
38
+ def sccb(s)
39
+ return ccb(s) % 100
40
+ end
41
+ # :end :sccb
42
+
43
+ =begin rdoc
44
+
45
+ "Randomized" version of sccb that uses prime numbers to do
46
+ a better job of scattering words more evenly.
47
+
48
+ =end
49
+
50
+ # :begin :rccb
51
+ def rccb(s)
52
+ return (s[0].ord * 31 + s[1].ord * 107) % 100
53
+ end
54
+ # :end :rccb
55
+
56
+ =begin rdoc
57
+
58
+ Compute the sum of the letters in a string, where each letter is weighted
59
+ according to its position. Requires the +ord+ method added to Fixnum in the
60
+ RubyLabs module.
61
+
62
+ =end
63
+
64
+ # :begin :radix26
65
+ def radix26(s)
66
+ x = 0
67
+ s.each_byte do |b|
68
+ x = x * 26 + b.ord
69
+ end
70
+ return x
71
+ end
72
+ # :end :radix26
73
+
74
+ =begin rdoc
75
+ Trival hash function that uses only the first letter in the input string. +s+ is the
76
+ string to hash, +n+ is the size of the hash table.
77
+ =end
78
+
79
+ # :begin :h0
80
+ def h0(s, n)
81
+ return s[0].ord % n
82
+ end
83
+ # :end :h0
84
+
85
+ =begin rdoc
86
+ Slightly better hash function that uses the first two letters in the input string. +s+ is the
87
+ string to hash, +n+ is the size of the hash table.
88
+ =end
89
+
90
+ # :begin :h1
91
+ def h1(s, n)
92
+ return ((s[0].ord * 26) + s[1].ord) % n
93
+ end
94
+ # :end :h1
95
+
96
+ =begin rdoc
97
+ Hash function based on the radix-26 representation of the input string. +s+ is the
98
+ string to hash, +n+ is the size of the hash table.
99
+ =end
100
+
101
+ # :begin :hn
102
+ def hn(s, n)
103
+ return radix26(s) % n
104
+ end
105
+ # :end :hn
106
+
107
+ alias h hn
108
+
109
+ =begin rdoc
110
+
111
+ Make a hash table with +n+ buckets. The optional parameter is a symbol specifying
112
+ an alternative hash function (<tt>:h0</tt> or <tt>:h1</tt>); the default is the method +hn+, which
113
+ uses the radix26 function.
114
+
115
+ The object returned by this method is an array of the designated size. A bit of
116
+ Ruby magic defines three new methods just for the new object:
117
+ [<tt>h=(f)</tt>] tells the table to use method f for the hash function (:h0, :h1, or nil)
118
+ [<tt>h</tt>] returns the id of the hash function currently being used
119
+ [<tt>hash(s)</tt>] call the current hash function on string s
120
+
121
+ =end
122
+
123
+ def make_table(n, f = nil)
124
+ t = Array.new(n)
125
+
126
+ class <<t
127
+ attr_accessor :h
128
+
129
+ def hash(s)
130
+ return case self.h
131
+ when :h0 : h0(s, self.size)
132
+ when :h1 : h1(s, self.size)
133
+ else hn(s, self.size)
134
+ end
135
+ end
136
+ end
137
+
138
+ t.h = f
139
+ return t
140
+ end
141
+
142
+ =begin rdoc
143
+ Return +true+ or +false+, depending on whether string +s+ is in hash table +t+. The
144
+ table must be an object created by a call to <tt>make_table</tt>.
145
+ =end
146
+
147
+ # :begin :find
148
+ def find(s, t)
149
+ i = t.hash(s)
150
+ return (t[i] == s)
151
+ end
152
+ # :end :find
153
+
154
+ =begin rdoc
155
+ Insert string +s+ into hash table +t+. The
156
+ table must be an object created by a call to <tt>make_table</tt>.
157
+ =end
158
+
159
+ # :begin :insert
160
+ def insert(s, t)
161
+ i = t.hash(s)
162
+ if t[i].nil?
163
+ t[i] = s
164
+ return true
165
+ else
166
+ puts "collision!"
167
+ return false
168
+ end
169
+ end
170
+ # :end :insert
171
+
172
+ =begin rdoc
173
+ Print a nicely formatted representation of hash table +t+. The optional parameter
174
+ is the number of rows to print, e.g. to print just the first 10 rows of a large table
175
+ +t+ call <tt>print_table(t,10)</tt>. Skips rows that have empty buckets.
176
+ =end
177
+
178
+ def print_table(t, max = nil)
179
+ max = t.length unless max
180
+ max.times { |i| print_row(i, t) unless t[i].nil? }
181
+ nil
182
+ end
183
+
184
+ def print_row(n, t) # :nodoc:
185
+ printf "%4d: ", n
186
+ p t[n]
187
+ end
188
+
189
+ =begin rdoc
190
+ Print usage statistics for hash table +t+. Prints lengths of longest and shortest
191
+ buckets, number of empty buckets, and mean bucket length.
192
+ =end
193
+
194
+ def print_stats(t)
195
+ max = 0
196
+ min = Float::MAX
197
+ nzero = 0
198
+ sum = 0
199
+ t.each do |bucket|
200
+ n = bucket.nil? ? 0 : bucket.length
201
+ min = n if n < min
202
+ max = n if n > max
203
+ sum += n
204
+ nzero += 1 if n == 0
205
+ end
206
+ puts "shortest bucket: #{min} items"
207
+ puts "longest bucket: #{max} items"
208
+ puts "empty buckets: #{nzero}"
209
+ puts "mean bucket length: #{sum.to_f / (t.length - nzero)}" unless nzero == t.length
210
+ nil
211
+ end
212
+
213
+ =begin rdoc
214
+ Scan the hash table +t+ and print all the buckets that have more than +cutoff+ entries.
215
+ =end
216
+
217
+ def print_long_rows(t, cutoff = 5)
218
+ t.length.times { |i| print_row(i, t) if !t[i].nil? && t[i].length >= cutoff }
219
+ nil
220
+ end
221
+
222
+ end # HashLab
223
+
224
+ end # RubyLabs
data/lib/introlab.rb ADDED
@@ -0,0 +1,14 @@
1
+ =begin rdoc
2
+
3
+ Fahrenheit to Celsius conversion.
4
+
5
+ =end
6
+
7
+ =begin rdoc
8
+ Convert the temperature +f+ (in degrees Fahrenheit) into the equivalent
9
+ temperature in degrees Celsius.
10
+ =end
11
+
12
+ def celsius(f)
13
+ (f - 32) * 5 / 9
14
+ end
@@ -0,0 +1,130 @@
1
+
2
+ =begin rdoc
3
+
4
+ == IterationLab
5
+
6
+ The methods implemented in this module are
7
+ +contains?+ (linear search returning true or false),
8
+ +location+ (linear search returning the index of specified item), and
9
+ +isort+ (insertion sort). See the RecursionLab module for more
10
+ sophisticated "divide and conquer" searching and sorting algorithms.
11
+
12
+ =end
13
+
14
+ module RubyLabs
15
+
16
+ module IterationLab
17
+
18
+ =begin rdoc
19
+ Do a linear search of array +a+ to find item +key+, returning
20
+ +true+ or +false+ depending on whether the item was found.
21
+ =end
22
+
23
+ # :begin :contains?
24
+ def contains?(a, k)
25
+ a.each { |x| return true if x == k}
26
+ return false
27
+ end
28
+ # :end :contains?
29
+
30
+ =begin rdoc
31
+ Do a linear search of array +a+ to find item +k+, returning
32
+ the index of the first occurrence of +k+ or +nil+ if +k+ is
33
+ not found.
34
+ =end
35
+
36
+ # :begin :search
37
+ def search(a, k)
38
+ i = 0
39
+ while i < a.length
40
+ return i if a[i] == k
41
+ i += 1
42
+ end
43
+ return nil
44
+ end
45
+ # :end :search
46
+
47
+ =begin rdoc
48
+ Return a copy of +array+, sorted with the insertion sort algorithm.
49
+ On each iteration remove an item from the
50
+ array, find a location for it to the left of its original position,
51
+ and insert it back into the array at the new location.
52
+ =end
53
+
54
+ # :begin :isort :insert_left :less
55
+ def isort(array)
56
+ a = array.clone # don't modify the input array....
57
+ i = 1
58
+ while i < a.length
59
+ insert_left(a, i) # find a place for a[i] somewhere to the left
60
+ i += 1
61
+ end
62
+ return a
63
+ end
64
+ # :end :isort
65
+
66
+ # :begin :insert_left
67
+ def insert_left(a, i)
68
+ x = a.slice!(i) # remove the item at location i
69
+ j = i-1 # start scanning from the left of i
70
+ while j >= 0 && less(x, a[j])
71
+ j = j-1 # move left
72
+ end
73
+ a.insert(j+1, x) # insert x back into a at location j
74
+ end
75
+ # :end :insert_left
76
+
77
+ # :begin :less
78
+ def less(x, y)
79
+ return x < y
80
+ end
81
+ # :end :less
82
+
83
+ =begin rdoc
84
+ Simple demonstration of why nested loops lead to n^2 operations
85
+ =end
86
+
87
+ # :begin :nested
88
+ def nested(n)
89
+ n.times do |i|
90
+ n.times do |j|
91
+ puts "i = #{i}, j = #{j}"
92
+ end
93
+ end
94
+ end
95
+ # :end :nested
96
+
97
+ # code used in figure next to nested
98
+
99
+ def isnest(n)
100
+ i = 1
101
+ while i < n
102
+ j = i-1
103
+ while j >= 0
104
+ puts "i = #{i}, j = #{j}"
105
+ j = j-1
106
+ end
107
+ i = i+1
108
+ end
109
+ end
110
+
111
+ =begin rdoc
112
+ A helper method that can be called from a probe to display the contents
113
+ of an array during a search or sort.
114
+ =end
115
+
116
+ def brackets(a, i)
117
+ if i <= 0
118
+ return ("[" + a.join(" ") + "]")
119
+ elsif i >= a.length
120
+ return " " + a.join(" ") + " [ ]"
121
+ else
122
+ pre = a.slice(0..(i-1))
123
+ post = a.slice(i..-1)
124
+ return " " + pre.join(" ") + " [" + post.join(" ") + "]"
125
+ end
126
+ end
127
+
128
+ end # IterationLab
129
+
130
+ end # RubyLabs
data/lib/randomlab.rb ADDED
@@ -0,0 +1,294 @@
1
+
2
+ =begin rdoc
3
+
4
+ == RandomLab
5
+
6
+ Random number generators and associated methods.
7
+
8
+ =end
9
+
10
+ module RubyLabs
11
+
12
+ module RandomLab
13
+
14
+ require 'statistics2.rb'
15
+
16
+ =begin rdoc
17
+ Simple random number generator, using "roulette wheel" algorithm.
18
+ =end
19
+
20
+ class Wheel
21
+
22
+ @@x = 0
23
+ @@c = 337
24
+ @@m = 1000
25
+
26
+ def Wheel.rand(n)
27
+ @@x = (@@x + @@c) % @@m
28
+ return @@x % n
29
+ end
30
+
31
+ def Wheel.params(*args)
32
+ if args.length == 0
33
+ return [@@x, @@m, @@c]
34
+ elsif args.length == 3
35
+ @@x, @@m, @@c = args
36
+ else
37
+ raise "params: expected 3 integers"
38
+ end
39
+ end
40
+ end
41
+
42
+ =begin rdoc
43
+ Better random number generator, using parameters from Numerical Recipes in C.
44
+ =end
45
+
46
+ class PRNG
47
+
48
+ @@x = 0
49
+ @@a = 3
50
+ @@c = 337
51
+ @@m = 1000
52
+
53
+ def PRNG.rand(n)
54
+ @@x = (@@x * @@a + @@c) % @@m
55
+ return @@x % n
56
+ end
57
+
58
+ def PRNG.params(*args)
59
+ if args.length == 0
60
+ return [@@x, @@m, @@a, @@c]
61
+ elsif args.length == 4
62
+ @@x, @@m, @@a, @@c = args
63
+ else
64
+ raise "params: expected 4 integers"
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ # :begin :uniform_test
71
+ def uniform_test(n, m, opt = nil)
72
+ bins = Array.new(m,0)
73
+ n.times { x = rand(m); bins[x] += 1 }
74
+ exp = Array.new(m, n/m)
75
+ if opt == :trace
76
+ print "bins: "
77
+ p bins
78
+ end
79
+ return chi_square_test(bins, exp, opt)
80
+ end
81
+ # :end :uniform_test
82
+
83
+ # :begin :poker_test
84
+ def poker_test(n, opt = nil)
85
+ types = [:nada, :pair, :two_pair, :three_of_a_kind, :full_house, :straight, :flush, :four_of_a_kind, :straight_flush]
86
+ counts = Hash.new
87
+ types.each { |x| counts[x] = 0 }
88
+ n.times do
89
+ h = random_deal(5)
90
+ # p h
91
+ t = poker_hand(h)
92
+ counts[t] += 1
93
+ end
94
+ return counts
95
+ end
96
+ # :end :poker_test
97
+
98
+ =begin rdoc
99
+ Compute the chi-square statistic for a set of bins containing results from n random draws.
100
+ The two parameters are arrays of equal length, containing the observed and expected values.
101
+ Return +true+ if the chi-square is less than the critical value for p = 0.95 (i.e. return
102
+ false if the hypothesis that the distributions are the same is rejected).
103
+ =end
104
+
105
+ def chi_square_test(obs, exp, opt = nil)
106
+ x2 = chi_square(obs, exp)
107
+ p = Statistics2.chi2dist(obs.length-1, x2)
108
+ if opt == :trace
109
+ printf "chi-square: %7.3f p = %.2f\n", x2, p
110
+ end
111
+ return p < 0.95
112
+ end
113
+
114
+ def chi_square(obs, exp)
115
+ sum = 0.0
116
+ for i in 0...obs.length
117
+ sum += ( (obs[i] - exp[i])**2 ).to_f / exp[i]
118
+ end
119
+ return sum
120
+ end
121
+
122
+ =begin rdoc
123
+ Make a random array of +n+ Card objects (selected without replacement).
124
+ =end
125
+
126
+ def random_deal(n)
127
+ h = Hash.new
128
+ while h.size < n
129
+ h[ rand(52) ] = 1
130
+ end
131
+ a = Array.new
132
+ h.keys.each do |x|
133
+ a << Card.new(x)
134
+ end
135
+ return a
136
+ end
137
+
138
+ =begin rdoc
139
+ Make a hand using numbers in array +a+ (used for testing)
140
+ =end
141
+
142
+ def deal(a)
143
+ a.map { |x| Card.new(x) }
144
+ end
145
+
146
+ =begin rdoc
147
+ Return a random shuffling of all 52 cards
148
+ =end
149
+
150
+ def shuffle
151
+ permutation((0..51).to_a).map { |x| Card.new(x) }
152
+ end
153
+
154
+ =begin rdoc
155
+ Classify a poker hand -- returns a symbol describing a hand. Return values:
156
+ :pair
157
+ :two_pair
158
+ :three_of_a_kind
159
+ :full_house
160
+ :straight
161
+ :flush
162
+ :four_of_a_kind
163
+ :straight_flush
164
+ =end
165
+
166
+ # TODO: royal flush in RAND test?
167
+
168
+ def poker_hand(a)
169
+ rcount = Array.new(Card::Ranks.length, 0)
170
+ scount = Array.new(Card::Suits.length, 0)
171
+ a.each do |x|
172
+ rcount[ Card::Ranks.index(x.rank) ] += 1
173
+ scount[ Card::Suits.index(x.suit) ] += 1
174
+ end
175
+ if rcount.max == 1
176
+ straight = (rcount.rindex(1) - rcount.index(1) == 4)
177
+ flush = scount.max == 5
178
+ return :straight_flush if (straight && flush)
179
+ return :straight if straight
180
+ return :flush if flush
181
+ return :nada
182
+ else
183
+ rcount.reject! { |x| x == 0 }
184
+ rcount.sort! { |x,y| y <=> x }
185
+ return :four_of_a_kind if rcount[0] == 4
186
+ return :full_house if (rcount[0] == 3 && rcount[1] == 2)
187
+ return :three_of_a_kind if rcount[0] == 3
188
+ return :two_pair if (rcount[0] == 2 && rcount[1] == 2)
189
+ return :pair
190
+ end
191
+ end
192
+
193
+
194
+ =begin rdoc
195
+ Class to represent cards from a standard 52-card deck. Includes comparators
196
+ to sort by rank or suit.
197
+
198
+ Call Card.new to get a random card, or Card.new(id) to get a specific card
199
+ where id is a number between 0 and 51.
200
+ =end
201
+
202
+ # To test the expression that assigns suits and ranks:
203
+ # 52.times { |x| puts (x/13).to_s + " " + (x%13).to_s }
204
+
205
+ class Card
206
+ attr_accessor :rank, :suit
207
+
208
+ unless defined? Suits
209
+ Suits = [:spades, :hearts, :diamonds, :clubs]
210
+ end
211
+
212
+ unless defined? Ranks
213
+ Ranks = [:ace, :king, :queen, :jack, :ten, :nine, :eight, :seven, :six, :five, :four, :three, :two]
214
+ end
215
+
216
+ def initialize(id = nil)
217
+ id = rand(52) if id.nil?
218
+ raise "card must be between 0 and 51" if id < 0 || id > 51
219
+ @suit = Suits[id / 13]
220
+ @rank = Ranks[id % 13]
221
+ end
222
+
223
+ def ==(x)
224
+ return @suit == x.suit && @rank == x.rank
225
+ end
226
+
227
+ def <=>(x)
228
+ r0 = Ranks.index(@rank); r1 = Ranks.index(x.rank)
229
+ s0 = Suits.index(@suit); s1 = Suits.index(x.suit)
230
+ if (res = (s0 <=> s1)) == 0
231
+ return (r0 <=> r1)
232
+ else
233
+ return res
234
+ end
235
+ end
236
+
237
+ @@outputform = :utf8
238
+
239
+ def inspect
240
+ s = ""
241
+ s << case @rank
242
+ when :ace : "A"
243
+ when :king : "K"
244
+ when :queen : "Q"
245
+ when :jack : "J"
246
+ when :ten : "10"
247
+ when :nine : "9"
248
+ when :eight : "8"
249
+ when :seven : "7"
250
+ when :six : "6"
251
+ when :five : "5"
252
+ when :four : "4"
253
+ when :three : "3"
254
+ when :two : "2"
255
+ end
256
+ if $KCODE[0] == ?U
257
+ if @@outputform == :utf8
258
+ s << case @suit
259
+ when :spades : "\xe2\x99\xa0"
260
+ when :hearts : "\xe2\x99\xa5"
261
+ when :clubs : "\xe2\x99\xa3"
262
+ when :diamonds : "\xe2\x99\xa6"
263
+ end
264
+ else
265
+ s << "!irb" + @suit.to_s.chop
266
+ end
267
+ else
268
+ s << case @suit
269
+ when :spades : "S"
270
+ when :hearts : "H"
271
+ when :clubs : "C"
272
+ when :diamonds : "D"
273
+ end
274
+ end
275
+ return s
276
+ # "#{@rank} #{@suit}"
277
+ end
278
+
279
+ alias to_s inspect
280
+
281
+ def Card.print_latex
282
+ @@outputform = :latex
283
+ end
284
+
285
+ def Card.print_utf8
286
+ @@outputform = :utf8
287
+ end
288
+
289
+
290
+ end
291
+
292
+ end # RandomLab
293
+
294
+ end # RubyLabs