From: Joel VanderWerf Date: 2010-05-29T05:08:35+09:00 Subject: Re: A better way to write this function? 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: <: Enter; G = 9.8, c = 0.01, m = 10.0; v = 0.0, x = 0.0> <: Enter; G = 9.8, c = 0.01, m = 10.0; v = 0.979951001633293, x = 0.0489983667075> <: Enter; G = 9.8, c = 0.01, m = 10.0; v = 1.95980401306601, x = 0.195986933986642> ... ... <: Enter; G = 9.8, c = 0.01, m = 10.0; v = 47.9025429248678, x = 117.457075132208> <: Enter; G = 9.8, c = 0.01, m = 10.0; v = 48.8777039117133, x = 122.296088286671>