rubylabs 0.6.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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