How to implement something similar to fortran module variable passing

fortran

#1

Fortran modules can be used to pass variables “behind” the main program, so that one can pass arguments to functions which are called by third-party codes without changing their arguments. For example:

module Test
   double precision :: a
end module Test

program Main
    use Test
    a = 2.
    x0 = 10.  !  Initial guess
    fmin = minimizef(x0)
end program Main

function f(x)
   use Test
   f = a*x^2 ! The parameter "a" was declared in the module and modified in Main
end function f

function minimizef(x)
     some code that calls a function in the form f(x),
     and I don't want to modify this code, which might be
     an optimized routine written by someone else.
end function minimizef

How can I deal with a similar situation in Julia? Apparently I could define a module, but the “using” keyword puts the variables of the module in the global scope, which is not the same thing.

I am probably not getting the logic of Julia programming quite correctly. Probably there is a natural way to deal with such situations which I am not used to.

Thank you.


#2

Module level variables are only visible in the main program if there are exported by the module or if they are qualified. For example Test.a.

However only functions within the module can change the values of variables declared inside that module. So you’ll need something like

module Test
    a::Float64
   update_a(value)  = a = value
end

#main program
using Test
Test.update_a(2.0)
...
f(x) = Test.a*x^2
...

#3

Uhm… I think I got the idea. The main difference is that the function that modifies the variable must be inside the module where they were defined, and the variables are visible to all functions in that module. It is reasonable. Just to point out, I was trying to use a Cuba.jl numerical integration function, and your tip solved my issue, by using:

using Cuba

module Test

  min = 0
  max = 5

  function g(x)
    return sin((x-min)/max)
  end

  function scaled_integrand(x,f)
    f[1] = (g(min+(max-min)*x[1]))*(max-min)
  end

end

result, err = cuhre( Test.scaled_integrand, atol=1e-7, rtol=1e-7 )

println(result)

The problem was the the function must be scaled and defined with variables as arrays to be understood by the chure function.


#4

Probably you already know this, but the Julian way to handle this situation is with closures and anonymous functions. For example, if you have a function for univariate quadrature, say quad(f,a,b), and you want to be able to pass sine functions to it, but you don’t want to have to decide on the frequency coefficient omega in advance, you would say:
quad(t -> sin(omega*t), a, b). The parameter omega is “hidden” from the quad routine.


#5

Thank you Stephen. I didn’t exactly know. Coming from a different background, it takes me some time to realize where some features might be useful. That would be a nice choice for my example, although for more complicated functions defining the function explicitly is probably more clear.

For the records, the above example would read, with this notation:

min = 0
max = 5
g(x) = sin((x-min)/max)
result, err = cuhre( (x,f) -> f[1] = (g(min+(max-min)*x[1]))*(max-min), atol=1e-7, rtol=1e-7 )
println(result)

Thank you!