How to implement "dependent constants" in a module

So from what I learned in Julia so far, constants make everything faster. So if I have a script that calculates a value that is dependent on the input of the script but then stays constant throughout the script (e.g. a Diffusion coefficient dependent on the chemical species I want to run the script for), I could implement something like this:

fizz = 4 #dependent on input, the "constant" for the rest of the script has another value

function foo(bar)
  return bar*3
end

const buzz = foo(fizz)

#do all calculations with a constant value of buzz

Now I want to implement this to in a module, but it’s not clear to me how to do it. Does anybody have some suggestions or examples?

The requirement for constants associated to performance is if they are used as global variables. If you pass the values as parameters to functions that is not needed.

Thus, if the calculations are performed in a function that receive as parameter the diffusion coefficient, you don’t need it to be declared constant.

(You can do something like you are asking, but it is not a common pattern).

2 Likes

Thank you for your quick reply, I understand but I think I still need to achieve it. Maybe my example was too minimal however. I try to explain it better:

Actually I have an algorithm implementing an inverse advection problem using Zygote. So I actually define something like


species = "ethanol"
v = 1.                      #velocity
n = 100                   #number of discretization points

function build_band_matrix(v,n,species)
    D = calculate_diffusion_coefficient(species)
    VB, DB = build_matrices(n) #discretization matrices for convection&diffusion
    band_matrix = v.*VB+D.*DB
    return band_matrix
end

In order to then use this band matrix together with the parameters to fit, I had to define

const ode_system_matrix = build_band_matrix(v,n,species)

#define and solve inverse problem with zygote

since Zygote does not work with mutables like my matrix building function. Now I would like to implement this kind of pipeline/sequence in a module.

Well, you can do that in a module, although I am not sure if that is really what you want:

julia> module M
         x = 2
         f(x) = 3*x
         const y = f(x)
       end

julia> using .M

julia> M.y
6


Yes I want to do something like this, but then also to be able to do something like redefining

M.x = 3

to retrieve M.y = 9 as a new constant for the rest of the functions implemented in M.
In other words I want the module to be able to calculations for different values of x (e.g read in from a file) but for the rest of the functions to work, M.y = f(M.x) has to be a constant. (Hence the borderline nonsensical title “dependent constants”.)

Maybe I’m also doing something fundamentally wrong.

I think the standard way is to define the build_band_matrix function in the module and let this command to be run by the user outside it, and then call the functions that use ode_system_matrix.

You might want to use a Struct as a container for those variables and pass it to your module functions.

struct S
    x 
    y 
    function S(x)
        y = 3*x
        new(x,y)
    end
end
function foo(myvar1,myvar2,stru)
    a = myvar2*stru.x 
    b = myvar1*stru.y
    return (a,b)
end

Unfortunately this isn’t possible. A constant needs to be, well, constant. Moreover, a constant is just a value–it doesn’t represent some kind of implicit computation that happens every time the inputs to some function change.

It seems like what you really want is the ability to take some function f(x, y) where y is given by build_band_matrix and then pass it to something like Zygote which only works if your function looks like g(x) with y fixed, right?

If that’s what you want, then you don’t need a constant or a global variable at all. Instead, you need a closure:

function main()
  y = build_band_matrix(species, v, n)
  func_to_differentiate = x -> f(x, y)  # you can also write `func_to_differentiate(x) = f(x, y)`
  do_zygote_stuff(func_to_differentiate)
end

You can write this more compactly as:

function main()
  do_zygote_stuff(x -> f(x, build_band_matrix(species, v, n)))
end
1 Like

Thank you @rdeits that was exactly what I was looking for.