Julia:矢量别名的宏

时间:2016-05-21 09:47:31

标签: macros metaprogramming julia

我希望能够允许我的包的用户以更加数学的方式定义函数,我认为宏是正确的方向。问题如下。该代码允许用户定义函数,然后在专门的求解器中使用这些函数来解决PDE。但是,为了使求解器更容易,一些输入是"矩阵"以你通常不会想到的方式。例如,求解器可以接受函数f(x,t),但x[:,1]是您认为的xx[:,2]是您的想法作为y(有时它是3D)。

更大的问题是,当PDE是非线性时,我将所有内容放在u向量中,而在许多情况下(如反应扩散方程),这些东西都被命名。所以在这种一般情况下,我希望能够写

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

并将其翻译为

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

我不喜欢我的宏观foo,所以我希望有人可以让我开始(或者如果宏不是正确的方法来解决这个问题,请解释原因)。

如果用户必须将正在翻译的内容提供给什么,那就太难了,但是我希望尽可能地使用它,所以不知何故知道它是什么? s到空间变量,因此之前的所有内容都是u的一部分,但之后是x的一部分。

1 个答案:

答案 0 :(得分:4)

宏的技巧"查找/替换"只是将处理传递给更新表达式args的递归函数。您的签名将作为一组符号出现,因此您可以遍历调用签名并添加两个dicts,将变量名称映射到列索引。然后在看到任何变量时递归替换arg树。这是未经测试的:

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

我为你留下了一些功课,但这应该让你开始。