我希望能够允许我的包的用户以更加数学的方式定义函数,我认为宏是正确的方向。问题如下。该代码允许用户定义函数,然后在专门的求解器中使用这些函数来解决PDE。但是,为了使求解器更容易,一些输入是"矩阵"以你通常不会想到的方式。例如,求解器可以接受函数f(x,t)
,但x[:,1]
是您认为的x
和x[:,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
的一部分。
答案 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
我为你留下了一些功课,但这应该让你开始。