rubylabs 0.7.4 → 0.7.5
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/bin/statistics2-0.53/statistics2.rb +0 -0
- data/bin/statistics2.rb +0 -0
- data/data/spheres/solarsystem.txt +1 -1
- data/data/spheres/urey.txt +1 -1
- data/lib/rubylabs.rb +1 -1
- data/lib/spherelab.rb +74 -58
- data/lib/tsplab.rb +33 -3
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.5
|
File without changes
|
data/bin/statistics2.rb
CHANGED
File without changes
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Solar system data, downloaded from JPL, from ephemeris created for Jan 1, 1970
|
2
2
|
# Format for each line:
|
3
3
|
# name, mass, posx, posy, posz, velx, vely, velz, dia, color
|
4
|
-
# where mass is in
|
4
|
+
# where mass is in kilograms; posx, posy, and posz are the 3d position vector (in meters)
|
5
5
|
# and velx, vely, and velz is the 3D velocity vector (m/sec). The last two items are
|
6
6
|
# for the visualization -- radius (in pixels) and color for drawing the body.
|
7
7
|
|
data/data/spheres/urey.txt
CHANGED
data/lib/rubylabs.rb
CHANGED
@@ -208,7 +208,7 @@ Similar to TestArray, but draws random words from a file.
|
|
208
208
|
|
209
209
|
class RandomArray < Array
|
210
210
|
|
211
|
-
data = File.join(File.dirname(__FILE__), '..', 'data')
|
211
|
+
data = File.join(File.dirname(__FILE__), '..', 'data', 'arrays')
|
212
212
|
|
213
213
|
@@sources = {
|
214
214
|
:cars => "#{data}/cars.txt",
|
data/lib/spherelab.rb
CHANGED
@@ -78,7 +78,8 @@ module SphereLab
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def inspect
|
81
|
-
|
81
|
+
pos = [@x,@y,@z].map { |x| sprintf "%.5g", x }
|
82
|
+
return "(" + pos.join(",") + ")"
|
82
83
|
end
|
83
84
|
|
84
85
|
=begin rdoc
|
@@ -187,32 +188,20 @@ module SphereLab
|
|
187
188
|
attr_accessor :mass, :position, :velocity, :force
|
188
189
|
attr_accessor :name, :size, :color, :prevx, :prevy, :graphic
|
189
190
|
|
190
|
-
=begin rdoc
|
191
|
-
The constructor can be called with a variety of different arguments:
|
192
|
-
* for the main n-body simulation, initial conditions are read from a data file,
|
193
|
-
and the constructor is passed three parameters: mass, position vector, and
|
194
|
-
velocity vector; an optional 4th parameter is a name string
|
195
|
-
* for interactive experiments, pass two floats, which become the mass and the
|
196
|
-
x component of the velocity; an optional 3rd parameter is the name
|
197
|
-
* also for interactive experiments pass :rand to make a body with random
|
198
|
-
mass, position, and velocity
|
199
|
-
* pass no parameters to get a body with all attributes set to 0
|
200
|
-
=end
|
201
|
-
|
202
191
|
def initialize(*args)
|
203
192
|
if args[1].class == Vector
|
204
193
|
@mass, @position, @velocity, @name = args
|
205
|
-
elsif args[0] == :random
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
elsif args[0].is_a?(Numeric) && args[1].is_a?(Numeric)
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
194
|
+
# elsif args[0] == :random
|
195
|
+
# @mass = rand(10000) * 1e6
|
196
|
+
# @position = Vector.new(rand(300)-150, rand(300)-150, 0)
|
197
|
+
# @velocity = Vector.new(rand(20)-10, rand(10)-5, 0)
|
198
|
+
# @name = "b" + self.object_id.to_s
|
199
|
+
# elsif args[0].is_a?(Numeric) && args[1].is_a?(Numeric)
|
200
|
+
# @mass = args[0]
|
201
|
+
# @position = Vector.new(args[1], 0.0, 0.0)
|
202
|
+
# @velocity = Vector.new(0.0, 0.0, 0.0)
|
203
|
+
# @name = args[2]
|
204
|
+
# @linear = true
|
216
205
|
else
|
217
206
|
@mass = 0.0
|
218
207
|
@position = Vector.new(0.0, 0.0, 0.0)
|
@@ -223,15 +212,8 @@ module SphereLab
|
|
223
212
|
end
|
224
213
|
|
225
214
|
def inspect
|
226
|
-
|
227
|
-
s
|
228
|
-
s << @mass.to_s + "g "
|
229
|
-
if @linear
|
230
|
-
s << "x: " + @position.x.to_s
|
231
|
-
else
|
232
|
-
s << @position.inspect + " " + @velocity.inspect
|
233
|
-
end
|
234
|
-
return s
|
215
|
+
name = @name ? @name : ""
|
216
|
+
return sprintf "%s: %.3g kg %s %s", name, @mass, @position.inspect, @velocity.inspect
|
235
217
|
end
|
236
218
|
|
237
219
|
=begin rdoc
|
@@ -447,7 +429,8 @@ module SphereLab
|
|
447
429
|
|
448
430
|
def random_vectors(r, i, n)
|
449
431
|
theta = (2 * PI / n) * i + (PI * rand / n)
|
450
|
-
radius = r + (r/3)*(rand-0.5)
|
432
|
+
# radius = r + (r/3)*(rand-0.5)
|
433
|
+
radius = r + r * (rand-0.5)
|
451
434
|
x = radius * cos(theta)
|
452
435
|
y = radius * sin(theta)
|
453
436
|
vtheta = (PI - theta) * -1 + PI * (rand-0.5)
|
@@ -459,19 +442,23 @@ module SphereLab
|
|
459
442
|
def random_velocity(v, r)
|
460
443
|
res = Vector.new(-r * cos)
|
461
444
|
end
|
445
|
+
|
446
|
+
# todo -- put mm, mr in global options
|
462
447
|
|
463
|
-
def random_bodies(n, big
|
448
|
+
def random_bodies(n, big)
|
464
449
|
big = 1 if big.nil?
|
465
450
|
moving = true if moving.nil?
|
466
451
|
res = []
|
467
452
|
mm = 1e12 # average mass
|
468
453
|
mr = 150 # average distance from origin
|
454
|
+
bigm = (mm * 100) / big
|
469
455
|
big.times do |i|
|
470
456
|
r, v = random_vectors(mr/2, i, big)
|
471
|
-
|
457
|
+
ms = (1 + (rand/2 - 0.25) )
|
458
|
+
b = Body.new(bigm*ms, r, v)
|
472
459
|
b.name = "b#{i}"
|
473
460
|
b.color = '#0080ff'
|
474
|
-
b.size = 10
|
461
|
+
b.size = 10*ms
|
475
462
|
res << b
|
476
463
|
end
|
477
464
|
(n-big).times do |i|
|
@@ -482,12 +469,24 @@ module SphereLab
|
|
482
469
|
b.size = 5
|
483
470
|
res << b
|
484
471
|
end
|
485
|
-
if !moving
|
486
|
-
res.each { |b| b.velocity.x = b.velocity.y = b.velocity.z = 0.0 }
|
487
|
-
end
|
488
472
|
return res
|
489
473
|
end
|
490
474
|
|
475
|
+
def falling_bodies(n)
|
476
|
+
raise "n must be 5 or more" unless n >= 5
|
477
|
+
a = random_bodies(n-1, n-1)
|
478
|
+
# b = Body.new(1e13, (a[0].position + a[1].position), Vector.new(0,0,0))
|
479
|
+
b = Body.new(1e13, (a[0].position + a[1].position)*0.85, Vector.new(0,0,0))
|
480
|
+
# pos = a[0].position
|
481
|
+
# (1..(n-2)).each { |i| pos.add( a[i].position ) }
|
482
|
+
# b = Body.new(1e14, pos * (1.0 / n), Vector.new(0,0,0))
|
483
|
+
b.name = "falling"
|
484
|
+
b.size = 5
|
485
|
+
b.color = 'red'
|
486
|
+
a.insert(0, b)
|
487
|
+
return a
|
488
|
+
end
|
489
|
+
|
491
490
|
=begin rdoc
|
492
491
|
Initialize a new n-body system, returning an array of body objects. The
|
493
492
|
parameter is the name of a predefined system, the name of a file, or the
|
@@ -500,7 +499,10 @@ module SphereLab
|
|
500
499
|
raise "usage: make_system(id)" unless args.length > 0
|
501
500
|
if args[0] == :random
|
502
501
|
raise "usage: make_system(:random, n, m)" unless args.length >= 2 && args[1].class == Fixnum
|
503
|
-
return random_bodies(args[1], args[2]
|
502
|
+
return random_bodies(args[1], args[2])
|
503
|
+
elsif args[0] == :falling
|
504
|
+
raise "usage: make_system(:falling, n)" unless args.length >= 1 && args[1].class == Fixnum
|
505
|
+
return falling_bodies(args[1])
|
504
506
|
end
|
505
507
|
filename = args[0]
|
506
508
|
if filename.class == Symbol
|
@@ -518,6 +520,16 @@ module SphereLab
|
|
518
520
|
b.size = a[-2].to_i
|
519
521
|
b.color = a[-1]
|
520
522
|
bodies << b
|
523
|
+
end
|
524
|
+
if args[0] == :urey
|
525
|
+
class <<bodies[0]
|
526
|
+
def height
|
527
|
+
return 0 if prevy.nil?
|
528
|
+
return position.y - prevy
|
529
|
+
end
|
530
|
+
# def height=(x)
|
531
|
+
# end
|
532
|
+
end
|
521
533
|
end
|
522
534
|
rescue
|
523
535
|
puts "error: #{$!}"
|
@@ -559,23 +571,33 @@ module SphereLab
|
|
559
571
|
Demonstrate adding force vectors by moving only one body
|
560
572
|
=end
|
561
573
|
|
562
|
-
def update_one(bodies,
|
563
|
-
b = bodies[
|
574
|
+
def update_one(bodies, time)
|
575
|
+
b = bodies[0]
|
564
576
|
if b.graphic.nil?
|
565
577
|
puts "display the system with view_system"
|
566
578
|
return nil
|
567
579
|
end
|
568
|
-
for j in
|
569
|
-
next if i == j
|
580
|
+
for j in 1...bodies.length
|
570
581
|
Body.interaction( b, bodies[j] )
|
571
582
|
end
|
572
583
|
b.move(time)
|
584
|
+
if @@drawing.options.has_key?(:dash)
|
585
|
+
@@drawing.options[:dashcount] = (@@drawing.options[:dashcount] + 1) % @@drawing.options[:dash]
|
586
|
+
if @@drawing.options[:dashcount] == 0
|
587
|
+
@@drawing.options[:pendown] = @@drawing.options[:pendown].nil? ? :track : nil
|
588
|
+
end
|
589
|
+
end
|
573
590
|
newx, newy = scale(b.position, @@drawing.origin, @@drawing.scale)
|
574
591
|
Canvas.move(b.graphic, newx-b.prevx, newy-b.prevy, @@drawing.options[:pendown])
|
575
592
|
b.prevx = newx
|
576
593
|
b.prevy = newy
|
577
594
|
b.clear_force
|
595
|
+
# puts b.velocity.norm
|
596
|
+
# if (speed = b.velocity.norm) > 7.5
|
597
|
+
# b.velocity.scale(7.5 / speed)
|
598
|
+
# end
|
578
599
|
Canvas.sync
|
600
|
+
return true
|
579
601
|
end
|
580
602
|
|
581
603
|
=begin rdoc
|
@@ -584,17 +606,17 @@ module SphereLab
|
|
584
606
|
=end
|
585
607
|
|
586
608
|
# :begin :step_system
|
587
|
-
def step_system(bodies,
|
609
|
+
def step_system(bodies, dt)
|
588
610
|
nb = bodies.length
|
589
611
|
|
590
|
-
for i in 0
|
591
|
-
for j in (i+1)
|
612
|
+
for i in 0..(nb-1) # compute all pairwise interactions
|
613
|
+
for j in (i+1)..(nb-1)
|
592
614
|
Body.interaction( bodies[i], bodies[j] )
|
593
615
|
end
|
594
616
|
end
|
595
617
|
|
596
618
|
bodies.each do |b|
|
597
|
-
b.move(
|
619
|
+
b.move(dt) # apply the accumulated forces
|
598
620
|
b.clear_force # reset force to 0 for next round
|
599
621
|
end
|
600
622
|
end
|
@@ -686,12 +708,6 @@ module SphereLab
|
|
686
708
|
mymax = earth.coords[1]
|
687
709
|
melon = Canvas.circle(mxmin, mymax, 5, :fill => blist[0].color)
|
688
710
|
blist[0].graphic = melon
|
689
|
-
class <<blist[0]
|
690
|
-
def height
|
691
|
-
return 0 if prevy.nil?
|
692
|
-
return position.y - prevy
|
693
|
-
end
|
694
|
-
end
|
695
711
|
scale = (mymax-mymin) / hmax.to_f
|
696
712
|
@@drawing = MelonView.new(blist, scale, blist[0].position.y, melon.coords, options)
|
697
713
|
Canvas.sync
|
@@ -706,7 +722,7 @@ module SphereLab
|
|
706
722
|
|
707
723
|
def position_melon(blist, height)
|
708
724
|
melon = blist[0]
|
709
|
-
if @@drawing
|
725
|
+
if @@drawing && blist[0].graphic
|
710
726
|
if height < 0 || height > @@drawing.options[:hmax]
|
711
727
|
puts "Height must be between 0 and #{@@drawing.options[:hmax]} meters"
|
712
728
|
return false
|
@@ -732,7 +748,7 @@ module SphereLab
|
|
732
748
|
my = melon.position.y
|
733
749
|
return "splat" if melon.prevy.nil? || my < melon.prevy
|
734
750
|
step_system(blist, dt)
|
735
|
-
if @@drawing
|
751
|
+
if @@drawing && blist[0].graphic
|
736
752
|
if @@drawing.options[:dash] > 0
|
737
753
|
@@drawing.options[:dashcount] = (@@drawing.options[:dashcount] + 1) % @@drawing.options[:dash]
|
738
754
|
if @@drawing.options[:dashcount] == 0
|
@@ -744,7 +760,7 @@ module SphereLab
|
|
744
760
|
Canvas.move(melon.graphic, dx, dy, @@drawing.options[:pendown])
|
745
761
|
Canvas.sync
|
746
762
|
end
|
747
|
-
return
|
763
|
+
return blist[0].height
|
748
764
|
end
|
749
765
|
|
750
766
|
# :begin :drop_melon
|
data/lib/tsplab.rb
CHANGED
@@ -126,7 +126,7 @@ minutes.
|
|
126
126
|
def coords(name)
|
127
127
|
return @coords[name]
|
128
128
|
end
|
129
|
-
|
129
|
+
|
130
130
|
# private methods -- return the key for a city (make a new one if necessary),
|
131
131
|
# get a time value from an input line, save a distance
|
132
132
|
|
@@ -247,6 +247,9 @@ inherited from a parent, and incremented whenever a mutation or crossover is app
|
|
247
247
|
|
248
248
|
=end
|
249
249
|
|
250
|
+
=begin
|
251
|
+
TODO don't give access to path (unless there's a way to make it read-only -- freeze it?)
|
252
|
+
=end
|
250
253
|
|
251
254
|
class Tour
|
252
255
|
attr_reader :id, :path, :cost, :matrix, :nm, :nx
|
@@ -292,6 +295,33 @@ inherited from a parent, and incremented whenever a mutation or crossover is app
|
|
292
295
|
end
|
293
296
|
end
|
294
297
|
|
298
|
+
# Another constructor -- return the next tour lexicographically
|
299
|
+
# following tour t
|
300
|
+
|
301
|
+
def Tour.next(t)
|
302
|
+
p = t.path.clone
|
303
|
+
n = p.length
|
304
|
+
# find largest j s.t. path[j] < path[j+1]
|
305
|
+
j = n-2
|
306
|
+
while j >= 0
|
307
|
+
break if p[j] < p[j+1]
|
308
|
+
j -= 1
|
309
|
+
end
|
310
|
+
return nil if j < 0
|
311
|
+
# find largest i s.t. path[j] < path[i]
|
312
|
+
i = n-1
|
313
|
+
loop do
|
314
|
+
break if p[j] < p[i]
|
315
|
+
i -= 1
|
316
|
+
end
|
317
|
+
# exchange path[j], path[i]
|
318
|
+
p[j], p[i] = p[i], p[j]
|
319
|
+
# reverse path from j+1 to end
|
320
|
+
tmp = p.slice!(j+1, n-1)
|
321
|
+
p += tmp.reverse
|
322
|
+
return Tour.new(t.matrix, p)
|
323
|
+
end
|
324
|
+
|
295
325
|
def to_s()
|
296
326
|
return "\##{@id}: #{@path} / #{@cost}"
|
297
327
|
end
|
@@ -342,12 +372,12 @@ inherited from a parent, and incremented whenever a mutation or crossover is app
|
|
342
372
|
@nm += t.nm
|
343
373
|
self
|
344
374
|
end
|
345
|
-
|
375
|
+
|
346
376
|
# private methods -- compute the cost of a path, given a matrix; apply
|
347
377
|
# mutations (point mutations, cross-overs)
|
348
378
|
|
349
379
|
private
|
350
|
-
|
380
|
+
|
351
381
|
def pathcost(m,s)
|
352
382
|
sum = m.distance(s[0],s[-1]) # link from end to start
|
353
383
|
for i in 0..s.length-2
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubylabs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- conery
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-03-
|
12
|
+
date: 2010-03-12 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|