2
votes

I want to be able to allow users of my package to define functions in a more mathematical manner, and I think a macro is the right direction. The problem is as follows. The code allows the users to define functions which are then used in specialized solvers to solve PDEs. However, to make things easier for the solver, some of the inputs are "matrices" in ways that you wouldn't normally wouldn't think they would be. For example, the solvers can take in functions f(x,t), but x[:,1] is what you'd think of as x and x[:,2] is what you'd think of as y (and sometimes it is 3D).

The bigger issues is that when the PDE is nonlinear, I place everything in a u vector, when in many cases (like Reaction-Diffusion equations) these things are named. So in this general case, I'd like to be able to write

@mathdefine f(RA,RABP,RAR,x,y,t) = RA*RABP + RA*x + RAR*t

and have it translate to

f(u,x,t) = u[:,1].*u[:,2] + u[:,1].*x[:,1] + u[:,3]*t

I am not up to snuff on my macro-foo, so I was hoping someone could get me started (or if macros are not the right way to approach this, explain why).

It's not too hard if the user has to give what is being translated to what, but I'd like to have it be as clean to use as possible, so somehow know that it's to the spatial variables and so everything before is part of a u, but after is part of x.

1

1 Answers

4
votes

The trick to macro "find/replace" is just to pass off processing to a recursive function that updates the expression args. Your signature will come in as a bunch of symbols, so you can loop through the call signature and add to two dicts, mapping variable name to column index. Then recursively replace the arg tree when you see any of the variables. This is untested:

function replace_vars!(expr::Expr, xd::Dict{Symbol,Int}, ud::Dict{Symbol,Int})
  for (i,arg) in enumerate(expr.args)
    if haskey(xd, arg)
      expr.arg[i] = :(x[:,$(xd[arg])])
    elseif haskey(ud, arg)
      expr.arg[i] = :(u[:,$(ud[arg])])
    elseif isa(arg,Expr)
      replace_vars!(arg, xd, ud)
    end
  end
end

macro mathdefine(expr)
  # todo: loop through function signature (expr.args[1]?) to build xd/ud
  replace_vars!(expr)
  expr
end

I left a little homework for you, but this should get you started.