Pass a formula as a function parameter in Julia
我正在尝试创建一个允许更改Julia中的公式和系数的函数。我80%确定我应该使用匿名函数吗?
这个使用python的SO帖子是我想要完成的一个更离散的例子(特别是chepner的基本python示例,而不是使用库)。在python中将公式作为函数参数传递
我还发现这个使用Julia的SO帖子,它使用一个类型来存储所需的参数,然后将它们传递给一个函数。如何将参数列表传递给Julia中的函数
使用这些作为基础,这是我到目前为止创建的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #Create composite type type Params formula b1::Float64 b2::Float64 end #create instance of type and load foo=Params((b1,b2,X)-> X^b1+X+b2,0.004,0.005) #create function function DoMath(X,p::Params) p.formula(X,varargs...) #?? end |
我是否正确地通过使用复合类型和/或lambdas来构建它?我没有任何CS培训,在尝试学习Julia的过程中,我在弄清楚了许多概念。
什么是允许用户更改公式和任何系数的函数的正确语法。对于给定的X?最终,我想象的功能如下:
1 2 3 | DoMath(4) #some default formula with changing X DoMath(4, X*b1 +X*b2) #change X and change formula DoMath(4, (X,b1,b2,b3)->X*b1+X*b2+x*b3) # change x, change formula to a 3 parameter function |
谢谢
更新:
我按照@Chris的语法开始工作。我不得不修补的一件事是使用
1 | (p::Params)(x) = p.formula(x,p.b) #p.b, not just b otherwise error |
我必须在调用之前将2.0和3.0包装在一个数组中
1 | p = Params((x,b)->x*b[1]+b[2],[2.0,3.0]) |
我们的想法是建立一个可调用的类型。可调用类型是具有"调用"的任何类型。函数
所以让我们为你的例子构建一个。使您的类型包含您想要的数据:
1 2 3 4 | type Params b1::Float64 b2::Float64 end |
现在让我们添加对
1 | (p::Params)(x) = x*p.b1 + p.b2 |
让我们看看它是如何工作的。做一个参数:
1 | p = Params(2.0,3.0) |
现在我们可以通过使用它的调用来计算公式:
1 | p(4) # 4*2+3 = 11 |
现在看到
其余的都是从同一个基础建立起来的。您需要尊重Julia类型不是动态的事实。这是有充分理由的。但是,假设你不知道你想要多少b。然后你可以让一个字段是一个
1 2 3 4 | type Params b::Vector{Float64} end (p::Params)(x) = x*b[1] + b[2] |
现在让我们假设您希望能够修改公式。然后你可以有一个公式字段:
1 2 3 4 | type Params formula b::Vector{Float64} end |
并使调用将值抛出到:
1 | (p::Params)(x) = p.formula(x,b) |
现在,如果用户做了:
1 | p = Params((x,b)->x*b[1]+b[2],2.0,3.0) |
然后,和以前一样:
1 | p(4) # 4*2+3 = 11 |
它的行为相同,仍然使用内部数据。
但由于
1 2 | p.formula = (x,b)-> x*b[1]+x*b[2]+b[3] push!(p.b,2.0) # p.b == [2.0,3.0,2.0] |
并再次调用,现在使用更新的字段:
1 | p(4) # 4*2 + 4*3 + 2 = 22 |
实际上,正如@LyndonWhite指出的那样,ParameterizedFunctions.jl实现了这样的东西。这样做的策略是可调用类型。
额外的小细节
构建(错误地)某些库需要用户传入函数。所以这里有一个
但是,有一个快速解决方案。只需将其
1 2 3 4 | type Params <: Function b1::Float64 b2::Float64 end |
现在需要函数的东西将使用
这是我目前用于处理这些"固定参数"与"更改参数"问题的类似模式。
固定参数是在运行特定程序时经常不会改变的参数(例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | abstract FormulaModel immutable Foo{F<:Function} <: FormulaModel formula2fixedparams::F fixedParam1::Float64 fixedParam2::Float64 end Foo(f, b1=5., b2=10.) = Foo(f, b1, b2) Foo() = Foo((x,b1,b2)->x^b1+x+b2) # default formula immutable Bar{F<:Function} <: FormulaModel formula3fixedparams::F fixed1::Float64 fixed2::Float64 fixed3::Float64 end Bar(b1,b2,b3) = Bar((x,b1,b2,b3)->b1*x+b2*x+b3*x, b1, b2, b3) Bar() = Bar(1.,2.,3.) @generated function DoMath(model::FormulaModel, changingParams...) fixedParams = [:(getfield(model, $i)) for i = 2:nfields(model)] func = :(getfield(model, 1)) # prepare some stuff quote # do something $func(changingParams..., $(fixedParams...)) # do something else end end julia> DoMath(Foo(), 4) 1038.0 julia> DoMath(Foo((x,y,b1,b2)->(b1*x+b2*y)), 4, 10) 120.0 julia> DoMath(Bar(), 4) 24.0 |