Julia:矢量别名宏

Julia: Macros for vector aliasing

我希望能够让我的包的用户以更数学的方式定义函数,我认为宏是正确的方向。问题如下。该代码允许用户定义函数,然后在专门的求解器中使用这些函数来求解 PDE。但是,为了让求解器更轻松,一些输入 "matrices" 的方式通常不会是您认为的。例如,求解器可以接受函数 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

我对我的 macro-foo 不满意,所以我希望有人能帮助我开始(或者如果宏不是解决这个问题的正确方法,请解释原因)。

如果用户必须提供正在翻译的内容并不太难,但我希望它尽可能干净地使用,所以不知何故知道它是空间变量等等一切之前是 u 的一部分,但之后是 x.

的一部分

宏 "find/replace" 的技巧只是将处理传递给更新表达式参数的递归函数。您的签名将以一堆符号的形式出现,因此您可以循环调用签名并添加到两个字典,将变量名称映射到列索引。然后在看到任何变量时递归地替换 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

我给你留了一点功课,但这应该能让你入门。