Dear all,

I was comparing the speed of Julia versus other languages (like Python or 
Fortran). As a test case I decided to check the speed when a function is 
passed to another one (for an example in a Ode solver). This is just a test 
case for situations that can arise, I know that there are very good ode 
solvers in Julia.

I have found that the following code is quite slow, as slow as Python.
function eusolverfun(fun::Function, n::Int64, tend::Float64, x0::Float64, y0
::Float64, a::Float64, b::Float64, c::Float64, d::Float64)
  x, y = x0, y0
  dt = tend/n
  for i=1:n
    dx, dy = fun(x, y, a, b, c, d)::(Float64,Float64)
    x = x + dx*dt
    y = y + dy*dt
  end
  return x, y
end
function predpreyeq(x::Float64, y::Float64, a::Float64, b::Float64, 
c::Float64, d::Float64)
    dx = x*(a-b*y)
    dy = -y*(c-d*x)
    return dx, dy
end
function fullcalc(n)
  tend = 5.0
  a, b, c, d = 1.5, 1.0, 3.0, 1.0
  x0, y0 = 1.0, 1.0
  x, y = eusolverfun(predpreyeq, 20, tend, x0, y0, a, b, c, d)
  @time x, y = eusolverfun(predpreyeq, n, tend, x0, y0, a, b, c, d)
end

fullcalc(int(1e7))

I much faster version, as fast as Fortran actually, is the following:
module genode
export Ode, eusolver
abstract Ode

function eusolver(ode::Ode, n, tend, x0, y0)
  x, y = x0, y0
  dt = tend/n
  for i=1:n
    dx, dy = eqfun(ode, x, y)
    x = x + dx*dt
    y = y + dy*dt
  end
  return x, y
end

eqfun(ode::Ode, x, y) = (x,y)

end

using genode
import genode.eqfun

immutable MyOde <: Ode
    a::Float64
    b::Float64
    c::Float64
    d::Float64
end

function eqfun(ode::MyOde, x, y)
    dx = x*(ode.a-ode.b*y)
    dy = -y*(ode.c-ode.d*x)
    return dx, dy
end

n = int(1E9)
w = MyOde(1.5, 1.0, 3.0, 1.0)
x, y = eusolver(w, 10, 5.0, 1.0, 1.0)

@time x, y = eusolver(w, n, 5.0, 1.0, 1.0)

On my windows machine the first program for n=1e7 gives:

elapsed time: 2.603235344 seconds (1600001792 bytes allocated, 40.55% gc 
time)

While the second one gives (n=1e9):
elapsed time: 6.615803974 seconds (208 bytes allocated)

Is there a way to code first version in order to be as fast as the second?
While the second version could be quite handy for passing parameters to the 
Ode, one still needs to declare a placeholder function (*eqfun(ode::Ode, 
...)* in module genode) and import it in order to allow the overloading of 
the function to take place. 

Thanks.




Reply via email to