geotree 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,153 @@
1
+ require 'test/unit'
2
+
3
+ require_relative '../lib/geotree/tools.rb'
4
+ req('blockfile diskblockfile')
5
+
6
+
7
+ #SINGLETEST = "test_200_recover_with_incorrect_password"
8
+ if defined? SINGLETEST
9
+ if main?(__FILE__)
10
+ ARGV.concat("-n #{SINGLETEST}".split)
11
+ end
12
+ end
13
+
14
+ class TestBlockFile < Test::Unit::TestCase #< MyTestSuite
15
+
16
+
17
+ # include BlockFile
18
+ # include LEnc
19
+
20
+ # Make a directory, if it doesn't already exist
21
+ def mkdir(name)
22
+ if !File.directory?(name)
23
+ Dir::mkdir(name)
24
+ end
25
+ end
26
+
27
+ def suite_setup
28
+ # pr("\n\n>>>> TestBlockFile setup\n\n")
29
+
30
+ # Make current directory = the one containing this script
31
+ main?(__FILE__)
32
+
33
+ @@testDir = "__temp_dirs__"
34
+ mkdir(@@testDir)
35
+
36
+
37
+ clean()
38
+ end
39
+
40
+
41
+ def clean
42
+ end
43
+
44
+ def build_bf
45
+ if !@bf
46
+ @bf = BlockFile.new(64)
47
+ end
48
+ end
49
+
50
+ def suite_teardown
51
+ # pr("\n\n<<<< TestBlockFile teardown\n\n")
52
+ end
53
+
54
+ def method_setup
55
+ # pr("\n\n\n")
56
+ end
57
+
58
+ def method_teardown
59
+ @bf = nil
60
+ end
61
+
62
+
63
+
64
+ def ex(args)
65
+ if args.is_a? String
66
+ args = args.split
67
+ end
68
+ args.concat(["-w", @@sourceDir, "-q"])
69
+ LEncApp.new().run(args)
70
+ end
71
+
72
+
73
+ # --------------- tests --------------------------
74
+
75
+ def test_100_create_block_file
76
+ build_bf
77
+ assert(@bf && !@bf.open?)
78
+ end
79
+ def test_110_create_and_open_block_file
80
+ build_bf
81
+ @bf.open
82
+ assert(@bf && @bf.open?)
83
+ end
84
+
85
+ def test_120_user_values
86
+ build_bf
87
+ @bf.open
88
+ k = 42
89
+ @bf.write_user(2,k)
90
+ @bf.write_user(1,k/2)
91
+ assert(@bf.read_user(2) == k)
92
+ assert(@bf.read_user(1) == k/2)
93
+ end
94
+
95
+ def test_130_read_when_not_open
96
+ assert_raise(IllegalStateException) do
97
+ build_bf
98
+ @bf.write_user(2,42)
99
+ end
100
+ end
101
+
102
+ def test_140_private_constant_access
103
+ assert_raise(NameError) do
104
+ BlockFile::BLOCKTYPE_RECYCLE
105
+ end
106
+ end
107
+
108
+ # def test_140_phony
109
+ # assert_raise(IllegalStateException) do
110
+ # puts "nothing"
111
+ # end
112
+ # end
113
+
114
+ end
115
+
116
+ if true && __FILE__ == $0
117
+
118
+ pth = '__foo__.bin'
119
+ remove_file_or_dir(pth)
120
+
121
+ bf = DiskBlockFile.new(64,pth)
122
+ bf.open
123
+
124
+ bnames = []
125
+ (20..40).each do |i|
126
+ by = bf.alloc_buffer
127
+ bf.block_size.times do |x|
128
+ by[x] = i.chr
129
+ end
130
+ # bf.write(n,by)
131
+ n = bf.alloc(by)
132
+ bnames << n
133
+ pr("i=#{i} n=#{n} block_size=%d\n",bf.block_size)
134
+ pr("alloc'd block #{n}:\n%s\n",n,bf.dump(n))
135
+ end
136
+
137
+ 5.times do
138
+ q = bnames.pop
139
+
140
+ bf.free q
141
+ pr("\n\n\nafter freeing %d: %s\n",q,d(bf))
142
+
143
+ if (q % 3 == 2)
144
+ q2 = bf.alloc
145
+ pr(" alloc'd another page #{q2}\n")
146
+ end
147
+
148
+ end
149
+
150
+ puts bf
151
+ bf.close
152
+ end
153
+
@@ -0,0 +1,139 @@
1
+ require 'test/unit'
2
+
3
+ require_relative '../lib/geotree/tools.rb'
4
+ req('externalsort')
5
+
6
+ include ExternalSortModule
7
+
8
+ class TestExternalSort < MyTestSuite
9
+ include ExternalSortModule
10
+
11
+ ELEM_SIZE = 16
12
+
13
+ # Make a directory, if it doesn't already exist
14
+ def mkdir(name)
15
+ if !File.directory?(name)
16
+ Dir::mkdir(name)
17
+ end
18
+ end
19
+
20
+ def suite_setup
21
+
22
+ # Make current directory = the one containing this script
23
+ main?(__FILE__)
24
+
25
+ @@test_dir = "workdir"
26
+ mkdir(@@test_dir)
27
+
28
+ @@path = File.join(@@test_dir,"_input_.dat")
29
+ raise Exception,"no test file found" if !File.file?(@@path)
30
+
31
+ @@path3 = File.join(@@test_dir,"_largefile_.dat")
32
+ end
33
+
34
+ def prepare_unsorted
35
+ @@path2 = File.join(@@test_dir,"_output_.dat")
36
+ remove_file_or_dir(@@path2)
37
+ FileUtils.cp(@@path,@@path2)
38
+
39
+ fs = File.size(@@path2)
40
+ File.truncate(@@path2, fs - fs % ELEM_SIZE)
41
+ end
42
+
43
+ def suite_teardown
44
+ # remove_file_or_dir(@@path3)
45
+ end
46
+
47
+ def method_setup
48
+ end
49
+
50
+ def method_teardown
51
+ end
52
+
53
+ def test_chunk
54
+ db = false
55
+
56
+ prepare_unsorted
57
+
58
+ f = File.open(@@path,"rb")
59
+ f2 = File.open(@@path2,"wb")
60
+
61
+ fs = File.size(@@path)
62
+ fs -= fs % ELEM_SIZE
63
+
64
+ ch = ChunkReader.new(f, 0, fs, ELEM_SIZE, 73 )
65
+
66
+ ch2 = ChunkWriter.new(f2,0,fs,ELEM_SIZE, 300 )
67
+
68
+ while !ch.done
69
+ !db|| puts(ch.peek_dump)
70
+
71
+ buff, offset = ch.read()
72
+ !db||pr("Read: %s",hex_dump_to_string(buff[offset,ch.element_size]))
73
+ ch2.write(buff,offset)
74
+ end
75
+ !db || pr("%s\n%s\n",d(ch),d(ch2))
76
+
77
+ end
78
+
79
+ def test_sort
80
+
81
+ db = false
82
+
83
+ prepare_unsorted
84
+
85
+ !db|| pr("before sorting:\n")
86
+ !db|| puts(hex_dump(read_text_file(@@path2)))
87
+ sr = Sorter.new(@@path2, ELEM_SIZE, nil, 90, 8)
88
+
89
+ sr.sort
90
+ !db|| pr("after sorting:\n")
91
+ !db|| puts(hex_dump(read_text_file(@@path2)))
92
+ end
93
+
94
+
95
+ def test_sort_large
96
+
97
+ elem_size = 16
98
+
99
+ if !File.file?(@@path3)
100
+ pr("Constructing LARGE file for sort test...\n")
101
+ f = File.open(@@path3,"wb+")
102
+ srand(1965)
103
+
104
+ a = 'abcdefghijklmnopABCDEFGHIJKLMNOP'.chars
105
+ a = a[0...elem_size]
106
+
107
+ tot = 10_000_000 / 20
108
+
109
+ tot.times do |i|
110
+ s = a.shuffle.join
111
+ f.write(s)
112
+ end
113
+ end
114
+
115
+ c1 = Proc.new do |x,y|
116
+ bx,ox = x
117
+ by,oy = y
118
+ bx[ox,elem_size] <=> by[oy,elem_size]
119
+ end
120
+ c2 = Proc.new do |x,y|
121
+ bx,ox = x
122
+ by,oy = y
123
+ bx[ox+1,elem_size-1] <=> by[oy+1,elem_size-1]
124
+ end
125
+
126
+ pr("Sorting file in one way...\n")
127
+
128
+ sr = Sorter.new(@@path3, elem_size, c2)
129
+ sr.sort
130
+
131
+ pr("Sorting file in another...\n")
132
+
133
+ sr = Sorter.new(@@path3, elem_size, c1)
134
+ sr.sort
135
+ pr("...done sorting\n")
136
+
137
+ end
138
+
139
+ end
@@ -0,0 +1,432 @@
1
+ require 'test/unit'
2
+
3
+ require_relative '../lib/geotree/tools.rb'
4
+ req('geotree pswriter multitree')
5
+
6
+ include GeoTreeModule
7
+
8
+ #SINGLETEST = "test_ps_output_multi"
9
+ if defined? SINGLETEST
10
+ if main?(__FILE__)
11
+ ARGV.concat("-n #{SINGLETEST}".split)
12
+ end
13
+ end
14
+
15
+ class TestGeoTree < MyTestSuite
16
+ # Make a directory, if it doesn't already exist
17
+ def mkdir(name)
18
+ if !File.directory?(name)
19
+ Dir::mkdir(name)
20
+ end
21
+ end
22
+
23
+ def rnd_subset(pts, frac = 0.3)
24
+ raise ArgumentError if pts.empty?
25
+
26
+ a = pts.dup
27
+ num = [(a.size * frac).to_i.ceil,a.size].min
28
+ srand(1977)
29
+ a.shuffle!
30
+ del = a.slice!(0..num)
31
+ rem = a
32
+ [del,rem]
33
+ end
34
+
35
+ def pt_set(set = 0)
36
+ assert(set < @@pts.size )
37
+ @@pts[set]
38
+ end
39
+
40
+ def rel_path(path)
41
+ File.join(@@test_dir,path)
42
+ end
43
+
44
+ def suite_setup
45
+ n_pts = 3000
46
+
47
+ # Make current directory = the one containing this script
48
+ main?(__FILE__)
49
+
50
+ @@test_dir = "workdir"
51
+ mkdir(@@test_dir)
52
+ @@tree_path = rel_path("_mytree_.dat")
53
+
54
+ clean()
55
+
56
+ @@pts = []
57
+ srand(7)
58
+
59
+ @@pts << DataPoint.rnd_many(n_pts)
60
+
61
+ p2 = DataPoint.rnd_many(n_pts/4)
62
+ i = 0
63
+ while i < p2.size
64
+ n = [p2.size-i, 200].min
65
+ pi = p2[i]
66
+ (i...i+n).each do |j|
67
+ pj = p2[j]
68
+ pj.loc.set_to(pi.loc)
69
+ end
70
+ i += n
71
+ end
72
+ p2.shuffle!
73
+
74
+ @@pts << p2
75
+
76
+ p3 = DataPoint.rnd_many(n_pts)
77
+ p3.each_with_index do |pt,i|
78
+ pt.loc=Loc.new(i*5,i*5)
79
+ end
80
+ @@pts << p3
81
+
82
+ srand(2000)
83
+ @@rects = Bounds.rnd_many(20)
84
+ end
85
+
86
+ def tree
87
+ @@t ||= GeoTree.open(@@tree_path)
88
+ end
89
+
90
+ def add_pts(set = 0, max_pts = 0)
91
+ ps = @@pts[set]
92
+ if max_pts > 0
93
+ ps = ps[0,max_pts]
94
+ end
95
+ ps.each{|dp| tree.add(dp)}
96
+ tree.buffering = false
97
+ end
98
+
99
+ def clean(delete_tree_file = true)
100
+ @@t = nil
101
+ return if !delete_tree_file
102
+ remove_file_or_dir(@@tree_path)
103
+ end
104
+
105
+ def suite_teardown
106
+ end
107
+
108
+ def method_setup
109
+ end
110
+
111
+ def method_teardown
112
+ end
113
+
114
+ # Construct list of data points lying within a rectangle
115
+ def pts_within_rect(pts,r)
116
+ names = pts.select{|pt| r.contains_point(pt.loc)}
117
+ end
118
+
119
+ def names(pt_list)
120
+ DataPoint.name_list(pt_list)
121
+ end
122
+
123
+ def query(tree, b, pts = nil)
124
+ pts ||= pt_set
125
+
126
+ db = false
127
+ !db || pr("query rect= #{b}\n")
128
+
129
+ !db || pr("tree find=#{tree.find(b)}\n")
130
+
131
+ f1 = names(tree.find(b))
132
+ f2 = names(pts_within_rect(pts,b))
133
+ !db || pr("Find #{b} returned:\n #{d(f1)}\n #{d(f2)}\n")
134
+
135
+ if (!(f1 == f2))
136
+ raise IllegalStateException, "Query tree, bounds #{b}, expected #{d(f2)}, got #{d(f1)}"
137
+ end
138
+ end
139
+
140
+ def test_create_tree
141
+ clean
142
+ tree
143
+ end
144
+
145
+ def test_add_points
146
+ clean
147
+ add_pts
148
+ # puts(tree.dump)
149
+ # puts("Tree stats:\n#{d2(tree.statistics)}\n")
150
+ end
151
+
152
+ def test_queries
153
+ clean
154
+ add_pts
155
+ bn = @@rects
156
+ bn.each{|b| query(tree,b)}
157
+ end
158
+
159
+ def test_remove
160
+ db = false
161
+ # db = true
162
+
163
+ @@pts.each_with_index do |pset,i|
164
+ clean
165
+
166
+ # Use buffering, since some point sets are very unbalanced
167
+ tree.buffering = true
168
+ add_pts(i)
169
+
170
+ pts = pset
171
+ while !pts.empty?
172
+
173
+ del, rem = rnd_subset(pts)
174
+ !db || pr("\nChose subset size #{del.size} of points #{pts.size}...\n")
175
+
176
+ # !db || puts(tree.dump)
177
+
178
+ if !del.empty?
179
+ # construct a copy of the first point to be removed, one with a slightly
180
+ # different location, to verify that it won't get removed
181
+ pt = del[0]
182
+ loc = pt.loc
183
+ while true
184
+ x = loc.x + rand(3)-1
185
+ y = loc.y + rand(3) - 1
186
+ break if x!=loc.x || y != loc.y
187
+ end
188
+
189
+ pt = DataPoint.new(pt.name, pt.weight, Loc.new(x,y))
190
+ !db || pr("Attempting to remove perturbed point #{pt}")
191
+ pt2 = tree.remove(pt)
192
+ assert(!pt2)
193
+ # !db || puts(tree.dump)
194
+
195
+ end
196
+
197
+ del.each do |pt|
198
+ !db || pr(" attempting to remove #{pt}\n")
199
+ # !db || puts(tree.dump)
200
+
201
+ dp = tree.remove(pt)
202
+ assert(dp,"failed to remove #{pt}")
203
+ end
204
+
205
+ # try removing each point again to verify we can't
206
+ del.each do |pt|
207
+ !db || pr(" attempting to remove #{pt} again\n")
208
+ dp = tree.remove(pt)
209
+ assert(!dp)
210
+ end
211
+ pts = rem
212
+
213
+ # !db || puts(tree.dump)
214
+ end
215
+
216
+ end
217
+ end
218
+
219
+ def test_buffering
220
+ db = false
221
+ # db = true
222
+
223
+ return if !db
224
+
225
+ !db || pr("test buffering\n")
226
+
227
+ clean
228
+ tree
229
+
230
+ tree.buffering = true
231
+ add_pts(2) #2,2000)
232
+ stat1 = tree.statistics
233
+ assert(stat1['leaf_depth (avg)'] < 2.6)
234
+ end
235
+
236
+ # Test using points expressed in terms of longitude(x) and latitude(y)
237
+ def test_latlong
238
+ db = false
239
+
240
+ clean
241
+ t = tree
242
+
243
+ pts = []
244
+
245
+ pts << Loc.new(57.9,-2.9) # Aberdeen
246
+ pts << Loc.new(19.26,-99.7) # Mexico City
247
+ pts << Loc.new(-26.12,28.4) # Johannesburg
248
+
249
+ pts.each_with_index do |pt,i|
250
+ t.add(DataPoint.new(1+i,0,pt))
251
+ end
252
+
253
+ !db||pr("pts:\n%s\n",d2(pts))
254
+
255
+ pts.each_with_index do |lc,i|
256
+ y,x = lc.latit, lc.longit
257
+ !db|| pr("y,x=#{y},#{x}\n")
258
+ b = Bounds.new(x-1,y-1,2,2)
259
+
260
+ r = t.find(b)
261
+ assert(r.size == 1)
262
+ end
263
+
264
+ end
265
+
266
+ def test_latlong_range_error
267
+ assert_raise(ArgumentError) do
268
+ b = Bounds.new(175.0,50,10,10)
269
+ end
270
+ end
271
+
272
+ def test_open_and_close
273
+
274
+ clean
275
+ t = tree
276
+ ps = pt_set(0)
277
+ npts = ps.size
278
+
279
+ ps.each do |dp|
280
+ t.add(dp)
281
+ end
282
+
283
+ t.close
284
+ @@t = nil
285
+
286
+ t = tree
287
+ ps2 = t.find(GeoTree.max_bounds)
288
+
289
+ assert(ps2.size == ps.size)
290
+ end
291
+
292
+ def plot_pts(w,pts,gray=0)
293
+ w.push(w.set_gray(gray))
294
+ plot_pts_colored(w,pts)
295
+ w.pop
296
+ end
297
+
298
+ def plot_pts_colored(w,pts,scale=1)
299
+ pts.each do |pt|
300
+ w.draw_disc(pt.loc.x,pt.loc.y,scale*0.3*(pt.weight+4))
301
+ end
302
+
303
+ end
304
+
305
+ def pt_on_circle(cx,cy,ang,rad)
306
+
307
+ x = cx + Math.cos(ang) * rad
308
+ y = cy + Math.sin(ang) * rad
309
+ Loc.new(x.to_i,y.to_i)
310
+ end
311
+
312
+ def prepare_tree(tree)
313
+
314
+ ps1 = pt_set(0)
315
+ ps1 = ps1[0,120]
316
+
317
+ srand(42)
318
+ ps2 = DataPoint.rnd_many(400)
319
+ ps2.each do |pt|
320
+ rs = rand*rand*500
321
+ pc = pt_on_circle(820,620,rand * 2*3.1415,rs)
322
+ pt.loc = pc
323
+ end
324
+ ps1.concat(ps2)
325
+
326
+ ps1.each{|x| tree.add(x)}
327
+ ps1
328
+ end
329
+
330
+ def prepare_ws(path)
331
+ b = Bounds.new(0,0,1000,1000)
332
+
333
+ w = PSWriter.new(rel_path(path))
334
+
335
+ w.set_logical_page_size(b.w,b.h)
336
+
337
+ w
338
+ end
339
+
340
+ def test_ps_output
341
+
342
+ tree = GeoTree.new
343
+ ps1 = prepare_tree(tree)
344
+ w = prepare_ws("tree.ps")
345
+ # ps1,w = prepare_ws(tree,"tree.ps")
346
+
347
+ 50.times do |i|
348
+ w.new_page("GeoTree")
349
+
350
+ a = i * 3.1415/18
351
+ rad = 30+i*8
352
+
353
+ pp = pt_on_circle(500,450,a,rad)
354
+ x = pp.x
355
+ y = pp.y
356
+
357
+ width = (200 * (20+i)) / 25
358
+ height = (width * 2)/3
359
+ r = Bounds.new(x-width/2,y-height/2,width,height)
360
+ pts = tree.find(r)
361
+ w.push(w.set_gray(0))
362
+ w.draw_rect(r.x,r.y,r.w,r.h )
363
+ w.pop
364
+
365
+ w.push(w.set_rgb(0.4,0.4,0.9))
366
+ plot_pts_colored(w,ps1)
367
+ w.pop
368
+
369
+ w.push(w.set_rgb(0.75,0,0))
370
+ plot_pts_colored(w,pts,1.5)
371
+ w.pop
372
+
373
+ end
374
+
375
+ w.close();
376
+ end
377
+
378
+ def test_ps_output_multi
379
+
380
+ tree_path = rel_path("_multitree_")
381
+
382
+ # Perform two passes. On the first,
383
+ # create the multitree and the points;
384
+ # on the second, open the tree and
385
+ # construct a plot.
386
+
387
+ ps1 = nil
388
+
389
+ [0,1].each do |pass|
390
+
391
+ if pass == 0
392
+ remove_file_or_dir(tree_path)
393
+ else
394
+ assert(File.directory?(tree_path))
395
+ end
396
+
397
+ ndetails = 5
398
+ tree = MultiTree.new(tree_path,ndetails)
399
+
400
+ if pass == 0
401
+ ps1 = prepare_tree(tree)
402
+ tree.close
403
+ else
404
+ w = prepare_ws("multi_tree.ps")
405
+
406
+ steps = 4
407
+ (ndetails*steps).times do |i|
408
+ dt = i/steps
409
+ w.new_page("MultiTree detail=#{dt}")
410
+
411
+ r = Bounds.new(10+i*16,190+i*10,700,600)
412
+
413
+ pts = tree.find(r,dt)
414
+
415
+ w.push(w.set_gray(0))
416
+ w.draw_rect(r.x,r.y,r.w,r.h )
417
+ w.pop
418
+
419
+ plot_pts(w,ps1,0.8)
420
+
421
+ w.push(w.set_rgb(0.75,0,0))
422
+ plot_pts_colored(w,pts,1.2)
423
+ w.pop
424
+
425
+ end
426
+ w.close();
427
+ end
428
+ end
429
+ end
430
+
431
+ end
432
+