rubylabs 0.7.4 → 0.7.5

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 CHANGED
@@ -1 +1 @@
1
- 0.7.4
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 grams; posx, posy, and posz are the 3d position vector (in meters)
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
 
@@ -1,5 +1,5 @@
1
1
  # Two body system: a 6.6 pound watermelon and the earth. The melon is
2
2
  # initially stationary on the the earth's surface.
3
3
 
4
- melon 3000 0 6.371E6 0 0 0 0 10 pink
4
+ melon 3.0 0 6.371E6 0 0 0 0 10 pink
5
5
  earth 5.9736E+24 0 0 0 0 0 0 1000 darkgreen
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
- sprintf "<%s, %s, %s>", @x.to_s, @y.to_s, @z.to_s
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
- @mass = rand(10000) * 1e6
207
- @position = Vector.new(rand(300)-150, rand(300)-150, 0)
208
- @velocity = Vector.new(rand(20)-10, rand(10)-5, 0)
209
- @name = "b" + self.object_id.to_s
210
- elsif args[0].is_a?(Numeric) && args[1].is_a?(Numeric)
211
- @mass = args[0]
212
- @position = Vector.new(args[1], 0.0, 0.0)
213
- @velocity = Vector.new(0.0, 0.0, 0.0)
214
- @name = args[2]
215
- @linear = true
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
- s = ""
227
- s << @name + ": " if @name
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, moving)
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
- b = Body.new(mm*100/big, r, v)
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], args[3])
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, i, time)
563
- b = bodies[i]
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 0...bodies.length
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, time)
609
+ def step_system(bodies, dt)
588
610
  nb = bodies.length
589
611
 
590
- for i in 0...nb # compute all pairwise interactions
591
- for j in (i+1)...nb
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(time) # apply the accumulated forces
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 dt
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
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-02 00:00:00 -08:00
12
+ date: 2010-03-12 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15