rubylabs 0.6.4 → 0.7.0
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.
- data/VERSION +1 -1
- data/lib/randomlab.rb +143 -224
- data/lib/rubylabs.rb +262 -38
- data/lib/spherelab.rb +566 -209
- data/lib/tsplab.rb +308 -276
- data/test/sphere_test.rb +32 -0
- metadata +2 -22
- data/data/aafreq.txt +0 -20
- data/data/cars.txt +0 -50
- data/data/century.txt +0 -1
- data/data/colors.txt +0 -64
- data/data/earth.yaml +0 -15
- data/data/fruit.txt +0 -45
- data/data/hacodes.txt +0 -35
- data/data/hafreq.txt +0 -16
- data/data/hvfreq.txt +0 -5
- data/data/nbody.R +0 -23
- data/data/nbody.out +0 -731
- data/data/nbody.pdf +0 -3111
- data/data/nbody.png +0 -0
- data/data/nbody3d.pdf +0 -3201
- data/data/outer.pdf +0 -182785
- data/data/solarsystem.txt +0 -17
- data/data/suits.txt +0 -1
- data/data/wordlist.txt +0 -210653
- data/lib/sortlab.rb +0 -213
- data/lib/viewer.rb +0 -65
data/lib/sortlab.rb
DELETED
@@ -1,213 +0,0 @@
|
|
1
|
-
|
2
|
-
=begin rdoc
|
3
|
-
|
4
|
-
== SortLab
|
5
|
-
|
6
|
-
Instrumented versions of the sorting algorithms described in the chapters
|
7
|
-
on iterative algorithms and recursive algorithms. The versions here are
|
8
|
-
not intended to be viewed by students -- those implementations are in the
|
9
|
-
modules named IterationLab and RecursionLab.
|
10
|
-
|
11
|
-
The three public methods implemented here are +isort+ (insertion sort),
|
12
|
-
+msort+ (mergesort), and +qsort+ (quicksort). The only required parameter
|
13
|
-
is an array to sort. A method will make a copy of the parameter and return
|
14
|
-
a sorted version of the copy.
|
15
|
-
|
16
|
-
An optional second parameter can be used when running experiments:
|
17
|
-
:trace print the state of the array after each iteration of the outer loop
|
18
|
-
:count return a count of the number of comparisons made instead of the sorted array
|
19
|
-
:timer return the execution time in seconds instead of the sorted array
|
20
|
-
|
21
|
-
=end
|
22
|
-
|
23
|
-
module RubyLabs
|
24
|
-
|
25
|
-
module SortLab
|
26
|
-
|
27
|
-
=begin rdoc
|
28
|
-
|
29
|
-
The Timer class implements a simpler timer. Call +Timer.start+ to start
|
30
|
-
the timer, and +Timer.stop+ to get the elapsed time since the call to
|
31
|
-
+Timer.start+.
|
32
|
-
=end
|
33
|
-
|
34
|
-
class Timer
|
35
|
-
|
36
|
-
def Timer.start
|
37
|
-
@@tstart = Time.now
|
38
|
-
end
|
39
|
-
|
40
|
-
def Timer.stop
|
41
|
-
return Time.now - @@tstart
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
=begin rdoc
|
47
|
-
Insertion sort.
|
48
|
-
=end
|
49
|
-
|
50
|
-
def isort(a, mode = nil)
|
51
|
-
a = a.clone
|
52
|
-
Timer.start if mode == :timer
|
53
|
-
count = 0
|
54
|
-
for i in 1..a.length - 1
|
55
|
-
puts isort_brackets(a,i) if mode == :trace
|
56
|
-
x = a.slice!(i)
|
57
|
-
j = i - 1
|
58
|
-
while j >= 0 && (count += 1) > 0 && a[j] > x
|
59
|
-
j = j - 1
|
60
|
-
end
|
61
|
-
a.insert(j + 1, x)
|
62
|
-
end
|
63
|
-
return case mode
|
64
|
-
when :count : count
|
65
|
-
when :timer : Timer.stop
|
66
|
-
else a
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
=begin rdoc
|
71
|
-
Helper method for printing the state of the array during insertion sort.
|
72
|
-
=end
|
73
|
-
|
74
|
-
def isort_brackets(a, i)
|
75
|
-
pre = (i == 0) ? [] : a.slice(0..(i-1))
|
76
|
-
post = (i <= a.length) ? a.slice(i..-1) : []
|
77
|
-
return "[" + pre.join(", ") + "] [" + post.join(", ") + "]"
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
# Merge sort. Makes a copy of the input Array, returns a sorted
|
82
|
-
# version of the copy. Uses a "helper function" named merge to
|
83
|
-
# combine successively bigger pieces of the input array.
|
84
|
-
|
85
|
-
def msort(a, mode = nil)
|
86
|
-
a = a.clone # don't modify the input array!
|
87
|
-
Timer.start
|
88
|
-
n = 1 # size of "pile" at each step
|
89
|
-
count = 0
|
90
|
-
while n < a.length
|
91
|
-
i = 0 # first pile starts here
|
92
|
-
while i < a.length
|
93
|
-
count += merge(a,i,n) # merge piles at a[i] and i+n, put at a[i]
|
94
|
-
print " [" + a[i..i+2*n-1].join(" ") + "] " if mode == :trace
|
95
|
-
i += 2*n # next pile starts at i+2n
|
96
|
-
end
|
97
|
-
puts if mode == :trace
|
98
|
-
n *= 2 # double the pile size
|
99
|
-
end
|
100
|
-
if mode == :timer
|
101
|
-
return Timer.stop
|
102
|
-
elsif mode == :count
|
103
|
-
return count
|
104
|
-
else
|
105
|
-
return a
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# "Helper function" to merge two "piles" in place. A call to this method
|
110
|
-
# merges n-element lists at a[i] and a[i+n] and stores the merged result
|
111
|
-
# in the array starting at a[i]. Uses an auxiliary list to hold items moved
|
112
|
-
# from a[i..i+n-1], then merges those into place at a[i+n].
|
113
|
-
|
114
|
-
def merge(a, i, n)
|
115
|
-
aux = []
|
116
|
-
j = k = i + n
|
117
|
-
kmax = i + 2*n
|
118
|
-
kmax = a.length if kmax > a.length
|
119
|
-
count = 0
|
120
|
-
# phase 1 -- copy items from a[i..i+n-1] to aux
|
121
|
-
while i < k
|
122
|
-
if a[j] && a[j] < a[i] && (aux.empty? || a[j] < aux[0])
|
123
|
-
aux << a[i]
|
124
|
-
a[i] = a[j]
|
125
|
-
j += 1
|
126
|
-
count += 1
|
127
|
-
elsif !aux.empty? && aux[0] < a[i]
|
128
|
-
aux << a[i]
|
129
|
-
a[i] = aux.shift
|
130
|
-
count += 1
|
131
|
-
end
|
132
|
-
i += 1
|
133
|
-
end
|
134
|
-
# phase 2 -- merge aux into empty slots in a[i+n..i+2n]
|
135
|
-
while k < kmax && ! aux.empty?
|
136
|
-
if j == kmax || a[j] > aux[0]
|
137
|
-
a[k] = aux.shift
|
138
|
-
else
|
139
|
-
a[k] = a[j]
|
140
|
-
j += 1
|
141
|
-
end
|
142
|
-
k += 1
|
143
|
-
count += 1
|
144
|
-
end
|
145
|
-
return count
|
146
|
-
end
|
147
|
-
|
148
|
-
# QuickSort, based on the description from Cormen et al. The interface is
|
149
|
-
# a method qsort, called with the array to sort and an optional mode parameter
|
150
|
-
# that specifies whether to count comparisons or measure execution time.
|
151
|
-
|
152
|
-
# The actual sorting is done by qs. The parameters (using notation from
|
153
|
-
# Cormen et al): p is the left boundary of the region to sort, and r is
|
154
|
-
# right boundary. The call to partition sets q, the new boundary between
|
155
|
-
# two sub-regions.
|
156
|
-
|
157
|
-
def qsort(a, mode = nil)
|
158
|
-
dup = a.clone
|
159
|
-
Timer.start
|
160
|
-
if mode == :timer
|
161
|
-
return Timer.stop
|
162
|
-
else
|
163
|
-
count = qs(dup, 0, a.length-1, mode)
|
164
|
-
return mode == :count ? count : dup
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
def qs(a, p, r, mode)
|
169
|
-
puts bracketed(a,p,r) if mode == :trace
|
170
|
-
if p < r
|
171
|
-
q, count = partition(a, p, r)
|
172
|
-
count += qs(a, p, q, mode)
|
173
|
-
count += qs(a, q+1, r, mode)
|
174
|
-
else
|
175
|
-
count = 0
|
176
|
-
end
|
177
|
-
return count
|
178
|
-
end
|
179
|
-
|
180
|
-
# Set the pivot (called x here) to the item on the left edge of the
|
181
|
-
# region, then extend the regions until they meet in the middle
|
182
|
-
|
183
|
-
def partition(a, p, r)
|
184
|
-
x = a[p]
|
185
|
-
i = p - 1
|
186
|
-
j = r + 1
|
187
|
-
count = 0
|
188
|
-
while true
|
189
|
-
loop { j = j - 1; count += 1; break if a[j] <= x }
|
190
|
-
loop { i = i + 1; count += 1; break if a[i] >= x }
|
191
|
-
if i < j
|
192
|
-
a[i], a[j] = a[j], a[i]
|
193
|
-
else
|
194
|
-
return j, count
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
def bracketed(a, left, right)
|
200
|
-
# puts "#{left}..#{right}"
|
201
|
-
tmp = []
|
202
|
-
tmp += a[ 0 .. (left-1) ] if left > 0
|
203
|
-
tmp << "["
|
204
|
-
tmp += a[ left .. right ] if right >= 0
|
205
|
-
tmp << "]"
|
206
|
-
tmp += a[ (right+1) .. (a.length-1) ] if right < a.length
|
207
|
-
return tmp.join(" ")
|
208
|
-
end
|
209
|
-
|
210
|
-
end # RecursionLab
|
211
|
-
|
212
|
-
end # RubyLabs
|
213
|
-
|
data/lib/viewer.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
|
2
|
-
=begin rdoc
|
3
|
-
|
4
|
-
== Viewer
|
5
|
-
|
6
|
-
A module for displaying graphical views of objects created in lab projects. A view
|
7
|
-
is a simple drawing canvas with no controls -- objects are drawn when students evaluate
|
8
|
-
expressions in an IRB session.
|
9
|
-
|
10
|
-
The communication between IRB and the canvas is mediated by a Linda tuple-space. When
|
11
|
-
this module is included in an IRB session it launches a Ruby program named 'bb.rb', which
|
12
|
-
implements a Rinda tuplespace, and then launches a viewer program that will extract
|
13
|
-
tuples that describe objects and draw representations of those objects. There are
|
14
|
-
different viewers for each lab, e.g. nbview.rb is the N-body project viewer that draws
|
15
|
-
circles to show the positions of planets.
|
16
|
-
|
17
|
-
This organization is pretty cumbersome, but it appears to be the best/only way to control
|
18
|
-
a graphical interface from an IRB session. Ideally IRB could create a canvas from a GUI
|
19
|
-
library like Tk or Wx, but the problem is that these libraries only update their widgets
|
20
|
-
from a top-level event loop. In Ruby 1.8, without native threads, the event loop doesn't
|
21
|
-
give control back to IRB. Launching a Wx-based viewer as a separate application and
|
22
|
-
communicating with it via Linda is working, but is not very responsive. For one-way
|
23
|
-
communication it seems to be adequate.
|
24
|
-
|
25
|
-
The code assumes the module is loaded by a require statement in a lab method that is called
|
26
|
-
to initialize a view for that lab. Since the code is loaded by a require the module is
|
27
|
-
loaded only once. Statements in the main body of the module set up the bulletin board
|
28
|
-
and do other one-time intializations.
|
29
|
-
|
30
|
-
=end
|
31
|
-
|
32
|
-
require 'drb/drb'
|
33
|
-
require 'rinda/tuplespace'
|
34
|
-
|
35
|
-
module RubyLabs
|
36
|
-
|
37
|
-
module Viewer
|
38
|
-
|
39
|
-
# Code to execute when the module is loaded (assumed to happen only once):
|
40
|
-
|
41
|
-
raise "for interactive use only" unless defined? IRB
|
42
|
-
|
43
|
-
DRb.start_service # ? was after launch of bb.rb
|
44
|
-
|
45
|
-
@@uri = "druby://localhost:53783"
|
46
|
-
@@bindir = File.join(File.dirname(__FILE__), '..', 'bin')
|
47
|
-
@@bb = IO.popen("#{@@bindir}/bb.rb")
|
48
|
-
@@ts = Rinda::TupleSpaceProxy.new(DRbObject.new(nil, @@uri))
|
49
|
-
|
50
|
-
at_exit do
|
51
|
-
Process.kill(9, @@bb.pid)
|
52
|
-
Process.kill(9, @@viewer.pid)
|
53
|
-
end
|
54
|
-
|
55
|
-
def write_tuple(tag, args)
|
56
|
-
puts "RubyLabs::Viewer::write_tuple #{tag} #{args} #{@@uri}"
|
57
|
-
end
|
58
|
-
|
59
|
-
def launch_viewer(name)
|
60
|
-
@@viewer = IO.popen("#{@@bindir}/#{name} #{@@uri}")
|
61
|
-
end
|
62
|
-
|
63
|
-
end # Viewer
|
64
|
-
|
65
|
-
end # RubyLabs
|