A better way to write this function?

Here is my attempt at Newton's second law in Ruby:

#c is the drag coefficent
#m is mass
#t is total time elapsed
#dt is time increment
#vi is the starting velocity

G = 9.8

def velocity(c, m, t, dt, vi)
  vel = []
  t += dt
  steps = t/dt

  steps.times do
    v = vi
    vi = v + ( G - c/m*v) * dt
    vel << v
  end
  return vel
end

Is there a better way to do write this function? It seems pretty
straight forward to me so I guess that might be a sign that it is fine
the way it is...?

What if I needed more speed but still wanted it in Ruby?

Thank you!

···

--
Posted via http://www.ruby-forum.com/.

Just a slight improvement

def velocity(c, m, t, dt, vi)
   vel =

   (t/dt + 1).times do
     vel << vi
     vi += ( G - c/m*v) * dt
   end

   vel
end

You could also do

def velocity(c, m, t, dt, vi)
   (t/dt + 1).times do
     yield vi
     vi += ( G - c/m*v) * dt
   end
end

and use it with a block.

Kind regards

  robert

···

On 28.05.2010 17:20, Jason Lillywhite wrote:

def velocity(c, m, t, dt, vi)
   vel =
   t += dt
   steps = t/dt

   steps.times do
     v = vi
     vi = v + ( G - c/m*v) * dt
     vel<< v
   end
   return vel
end

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

A couple small speedups. c/m never changes while the loop is running,
so compute it once when the loop starts, then reuse the value. And you
could replace the times loop by a while loop for another small
speedup.... but this is never going to be fast in ruby. If you want
fast, use C.

···

On 5/28/10, Jason Lillywhite <jason.lillywhite@gmail.com> wrote:

Here is my attempt at Newton's second law in Ruby:

#c is the drag coefficent
#m is mass
#t is total time elapsed
#dt is time increment
#vi is the starting velocity

G = 9.8

def velocity(c, m, t, dt, vi)
  vel =
  t += dt
  steps = t/dt

  steps.times do
    v = vi
    vi = v + ( G - c/m*v) * dt
    vel << v
  end
  return vel
end

Is there a better way to do write this function? It seems pretty
straight forward to me so I guess that might be a sign that it is fine
the way it is...?

What if I needed more speed but still wanted it in Ruby?

Jason Lillywhite wrote:

What if I needed more speed but still wanted it in Ruby?

Not quite pure ruby, but if it's acceptable to have a C backend, then you can use redshift. On my computer, if I create 20K of the objects below, they run (concurrently) at about "real" time, i.e. 1 sec process time per 1 sec simulation time. Also, it is more accurate than your integration algorithm, since it uses a higher-order Runge-Kutta integrator. Plus, there are other features suitable for discrete/continuous multi-agent simulation (algebraic equations, discrete state transitions, event synchronization, queues with pattern-matching like Erlang, dataflow ports like Simulink, link variables, delay flows, differentiation, interactive shell and debuggers, ...).

If you want to try this, unpack this tarball:

http://path.berkeley.edu/~vjoel/redshift/redshift-1.3.14.tgz

and put the lib dir on your RUBYLIB. Some of the examples expect gnuplot to be installed, but otherwise there are no deps.

However, you must be able to build extensions, i.e, have a working C compiler that is binary compatible with your ruby (gcc, msvc, and solaris work for me), so that redshift can translate the equations into C and compile them into ruby extensions. If native gems build on your system, you should be ok. Note that the first time you run a particular redshift program, there is a delay while this build happens (the build goes into a tmp dir under the current dir).

···

-----

require 'redshift'

class Thing < RedShift::Component
   continuous :v, :x
   constant :m, :c, :G # per-instance constants

   flow do
     # "differential" means Runge-Kutta 4th order integration; if
     # you replace that word with "euler", it uses forward Euler
     # integration, which gives exactly the same results as the
     # original poster's example. Usually, RK4 is significantly
     # more accurate than Euler.
     differential " v' = G - c/m * v "

     # just for fun, let's keep track of distance traveled
     differential " x' = v "
   end
end

world = RedShift::World.new
world.time_step = 0.1

thing = world.create Thing
thing.m = 10
thing.c = 0.01
thing.v = 0
thing.x = 0
thing.G = 9.8

p thing
world.evolve 5.0 do
   p thing
end

__END__

Output:

<<Thing 0>: Enter; G = 9.8, c = 0.01, m = 10.0; v = 0.0, x = 0.0>
<<Thing 0>: Enter; G = 9.8, c = 0.01, m = 10.0; v = 0.979951001633293, x = 0.0489983667075>
<<Thing 0>: Enter; G = 9.8, c = 0.01, m = 10.0; v = 1.95980401306601, x = 0.195986933986642>
...
<<Thing 0>: Enter; G = 9.8, c = 0.01, m = 10.0; v = 47.9025429248678, x = 117.457075132208>
<<Thing 0>: Enter; G = 9.8, c = 0.01, m = 10.0; v = 48.8777039117133, x = 122.296088286671>

Using C for the "fast" bits has been suggested.

As an alternative to C for speed, I've found that using JRuby with parts of
the code as Java functions works well.

Perhaps I ought to add that I've never tried compiling a C program and
integrating it with Ruby, because of my lack of knowledge of the finer - and
not so finer! - points of C compilation and integration with Ruby. But I've
found writing and compiling parts of the code that need to be fast fairly
easy in Java, and integration of Java with JRuby is also fairly
straightforward.

···

On Fri, May 28, 2010 at 4:20 PM, Jason Lillywhite < jason.lillywhite@gmail.com> wrote:

Here is my attempt at Newton's second law in Ruby:
  ...
What if I needed more speed but still wanted it in Ruby?

Jason Lillywhite wrote:

G = 9.8

def velocity(c, m, t, dt, vi)
  vel =
  t += dt
  steps = t/dt

  steps.times do
    v = vi
    vi = v + ( G - c/m*v) * dt
    vel << v
  end
  return vel
end

Is there a better way to do write this function?

You can make it a one-liner using range and map:

def velocity(c, m, t, dt, v)
  [v] + (0...t/dt).map { v += (G - c/m*v) * dt }
end

This version also works with float values of t and dt, which yours
rejects because there is no Float#times.

···

--
Posted via http://www.ruby-forum.com/\.

Joel VanderWerf wrote:

snip

Thank you Joel.

is this redshift you introduced to me the same thing as

??

···

--
Posted via http://www.ruby-forum.com/\.

I took a quick shot w/ duby-inline.

Host:
2.6.32-22-generic #33-Ubuntu SMP Wed Apr 28 13:27:30 UTC 2010 i686 GNU/Linux
Intel(R) Pentium(R) M processor 1.60GHz

Benchmark block:
100000.times{ velocity(0.5, 21.6, 600, 10, 0.0) }

"Original" code (see note below):

ruby 1.8.7 (2010-01-10 patchlevel 249) [i486-linux]
       user system total real
  18.210000 0.040000 18.250000 ( 21.596111)

jruby 1.5.0 (ruby 1.8.7 patchlevel 249) (2010-05-12 6769999) (OpenJDK
Client VM 1.6.0_18) [i386-java]
       user system total real
   4.525000 0.000000 4.525000 ( 4.525000)

jruby 1.5.0 (ruby 1.8.7 patchlevel 249) (2010-05-12 6769999) (OpenJDK
Server VM 1.6.0_18) [i386-java]
       user system total real
   3.651000 0.000000 3.651000 ( 3.651000)

Duby code:

jruby 1.5.0 (ruby 1.8.7 patchlevel 249) (2010-05-12 6769999) (OpenJDK
Client VM 1.6.0_18) [i386-java]
   0.415000 0.000000 0.415000 ( 0.415000)

jruby 1.5.0 (ruby 1.8.7 patchlevel 249) (2010-05-12 6769999) (OpenJDK
Server VM 1.6.0_18) [i386-java]
   0.208000 0.000000 0.208000 ( 0.208000)

I had to cheat a little bit and removed the array and the block to
make it Duby-compatible:

G = 9.8

class Newton
  def rb_velocity(c, m, t, dt, vi)
    t += dt
    steps = t/dt

    i = 0
    while i < steps
      v = vi
      vi = v + ( G - c/m*v) * dt
      i += 1
    end

    vi
  end
end

And, the duby version:

require 'inline'
require 'duby_inline'

G = 9.8

class Newton
  inline :Duby do |builder|
    builder.duby "
      def db_velocity(c:double, m:double, t:int, dt:int, vi:double)
        t += dt
        steps = t/dt

        i = 0
        while i < steps
          v = vi
          vi = v + ( #{G} - c/m*v) * dt
          i += 1
        end

        vi
      end
    "
  end
end

···

On Wed, Jun 2, 2010 at 11:44 PM, Colin Bartlett <colinb2r@googlemail.com> wrote:

On Fri, May 28, 2010 at 4:20 PM, Jason Lillywhite < > jason.lillywhite@gmail.com> wrote:

Here is my attempt at Newton's second law in Ruby:
...
What if I needed more speed but still wanted it in Ruby?

Using C for the "fast" bits has been suggested.

As an alternative to C for speed, I've found that using JRuby with parts of
the code as Java functions works well.

Jason Lillywhite wrote:

Joel VanderWerf wrote:

snip

Thank you Joel.

is this redshift you introduced to me the same thing as

RedShift download | SourceForge.net

Yes, that's the same thing (but there is no formal release on that site).

unknown wrote:

Duby code:
...snip

I'm sorry, can you tell me what Duby is? I tried looking it up and found
nothing. I'm familiar with JRuby but not Duby.

Thank you.

···

--
Posted via http://www.ruby-forum.com/\.

brabuhr@gmail.com wrote:

I took a quick shot w/ duby-inline.

...

ruby 1.8.7 (2010-01-10 patchlevel 249) [i486-linux]
       user system total real
  18.210000 0.040000 18.250000 ( 21.596111)

...

jruby 1.5.0 (ruby 1.8.7 patchlevel 249) (2010-05-12 6769999) (OpenJDK
Server VM 1.6.0_18) [i386-java]
   0.208000 0.000000 0.208000 ( 0.208000)

That is a very impressive speed-up!

I see a more modest improvement going from the same original code (on different hardware of course) to a version written in redshift. Of course, redshift is using a more accurate integration algorithm (with 4 substeps instead of 1). Plus there are costs for the availability of other features that are not being used in this example (e.g., a layer of function pointers so that variables can switch to different equations when a discrete state change occurs).

$ ruby bench-rb.rb
                   user system total real
evolve 6s 0.710000 0.160000 0.870000 ( 0.881276)
evolve 600s 15.320000 1.010000 16.330000 ( 16.366811)

$ ruby bench-rs.rb
                   user system total real
evolve 6s 0.020000 0.000000 0.020000 ( 0.025213)
evolve 600s 1.170000 0.000000 1.170000 ( 1.178752)

$ ruby -v
ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux]

Here are the sources:

$ cat bench-rb.rb
G = 9.8

def velocity(c, m, t, dt, vi)
   t += dt
   steps = t/dt

   i = 0
   while i < steps
     v = vi
     vi = v + ( G - c/m*v) * dt
     i += 1
   end

   vi
end

require 'benchmark'
Benchmark.bm(12) do |b|
   b.report("evolve 6s") do
     100000.times do
       velocity(0.5, 21.6, 6.0, 10.0, 0.0)
         # Note: I changed the t and dt to floats for a more direct
         # comparison with redshift, which uses floats for time values
     end
   end
   b.report("evolve 600s") do
     100000.times do
       velocity(0.5, 21.6, 600.0, 10.0, 0.0)
     end
   end
end

$ cat bench-rs.rb
require 'redshift'

class Thing < RedShift::Component
   continuous :v
   constant :m, :c, :G

   flow do
     differential " v' = G - c/m * v "
   end
end

def make_world(n)
   RedShift::World.new do |world|
     world.time_step = 10.0
     n.times do
       world.create Thing do |thing|
         thing.m = 21.6
         thing.c = 0.5
         thing.v = 0
         thing.G = 9.8
       end
     end
   end
end

require 'benchmark'
Benchmark.bm(12) do |b|
   n = 1000
   reps = 100
   # Note: instead of 100000 sequential runs, this benchmark is doing
   # 100 sequential runs of 1000 parallel instances of the same
   # integration problem, which is more typical of the conditions
   # redshift is optimized for

   world = make_world(n)
   b.report("evolve 6s") do
     reps.times do
       world.evolve 6.0
     end
   end

   world = make_world(n)
   b.report("evolve 600s") do
     reps.times do
       world.evolve 600.0
     end
   end
end

Joel VanderWerf wrote:

Jason Lillywhite wrote:

...

is this redshift you introduced to me the same thing as

RedShift download | SourceForge.net

Yes, that's the same thing (but there is no formal release on that site).

It's a gem now:

   gem install redshift

Duby is a Ruby-like static-typed language with local type inference
and not many bells and whistles. The primary motivation was to have a
Ruby-like language to implement parts of JRuby. Duby looks and feels
mostly like Ruby but compiles to tight JVM bytecode on par with what
you'd get from compiled Java.

def fib(a => :fixnum)
  if a < 2
    a
  else
    fib(a - 1) + fib(a - 2)
  end
end

puts fib(45)

···

On Mon, Jun 7, 2010 at 3:44 PM, Jason Lillywhite <jason.lillywhite@gmail.com> wrote:

unknown wrote:

Duby code:
...snip

I'm sorry, can you tell me what Duby is? I tried looking it up and found
nothing. I'm familiar with JRuby but not Duby.

Thank you.

unknown wrote:

Duby is a Ruby-like static-typed language...

Thank you for the links. Duby is really fast. thanks.

···

--
Posted via http://www.ruby-forum.com/\.