Julia Design:在宏中静默定义/命名类型

时间:2016-09-14 08:22:45

标签: types macros julia

我在定义新功能时遇到了一个开发问题,处理如何静默定义类型"。目前我有以下内容的宏:

f = @ode_define begin
dx = a*x - b*x*y
dy = -c*y + d*x*y
end a=>1.5 b=>1 c=3 d=1

将扩展为

f = (t,u,du) -> begin 
du[1] = 1.5*u[1] - u[1]*u[2]
du[2] = -3*u[2] + u[1]*u[2]
end

这些定义了在ODE求解器中使用的函数。 ODE求解器的一些特性需要知道参数(即灵敏度分析需要采用参数导数),所以为了使它更通用我想内联用=定义的参数,并且有一个"命名方式访问"用=>定义的参数。例如,我想将宏扩展为:

f,p = (t,u,du,p) -> begin 
du[1] = p.a*u[1] - p.b*u[1]*u[2]
du[2] = -3*u[2] + u[1]*u[2]
end

问题是,你如何定义参数?我可以让宏也这样做:

type Parameters
  a::Float64
  b::Float64
end
p = Parameters(a,b)

然后每个会话只能使用一次宏,因为每次都需要定义一个参数类型。有没有一种安全的方法来命名这种类型,以便可以重复使用宏?从本质上讲,参数类型并不意味着除了它是容纳ab的东西的容器之外,并且它可以通过名称访问(至关重要因为我计划做一些事情,询问你想要做哪些参数,比如分叉图。这就是我的意思"默默地" - 我希望宏吐出p p.ap.b工作,没有参考/没有用户必须关心如何定义它。此外,此设计路径还有一个限制,即无法在函数内部定义类型,因此该宏不能用于在函数内部定义ODE函数。

Julia是否提供了解决这些不牺牲性能的问题的好方法? (我可以使用字典,但这会导致性能下降)。

修改

总结设计目标,我想要一些东西,以便像我在开头展示的宏可以编写类似的代码:

f,p = (t,u,du,p) -> begin 
du[1] = p.a*u[1] - p.b*u[1]*u[2]
du[2] = -3*u[2] + u[1]*u[2]
end
type Parameters
  a::Float64
  b::Float64
end
p = Parameters(a,b)

致电

solve(f,p,y0)

在基本上用于

的解算器中使用
for i = 1:numiterations
  y = y + dt*f(t,u,du,p)
end

问题在于p的正确形式是否是一种类型,或者Julia是否还有其他东西可以用名称"来调用。如果它是一个类型,你如何解决类型必须具有唯一名称的事实(因此宏不能简单地将其扩展为类型参数,因为每次它可能有不同的字段)但是自动 - 生成一个只知道字段名称的类型?

1 个答案:

答案 0 :(得分:1)

gensym创建全局唯一名称,可以拼接到类型定义表达式,例如:

Expr(:type, true, gensym(:parameter), Expr(:(::), :x, :Int))
  

我可以使用字典,但这会导致性能下降

我不完全确定我理解这里的设计目标,但在您的示例中,您将实例p包装在闭包中。如果您将ODE名称设置为宏参数(@ode_def f = ...),那么您可以在f => f_metadata的某些全局字典中设置映射,其句柄为p以及您可能需要修改的任何内容。