Jason said:
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>