Function generating functions

Hello together,

Maybe this question is kind of trivial, but since I’m a Julia newbie I hoped to find some help and/or advice here. :wink:
I would like to fit different functions to some data. They only differ by one parameter k. The following code does not run. It is rather a “statement of intent” to explain what my goal is:

function model(x, p, k)
    sum([p[i]*(x.^i/factorial(i)) for i in 1:k])
end

for i in 1:10
    fit = curve_fit(model(.,.,i), x, y)
    ... some more code ...
end

It worked to a point, where different …things where generate ( of type var"#574#576") These objects can be evaluated and yield some value if provided with arguments. But the curve_fit function does not like this type of object. I tried to use something like:

function m(k)
    return :((x,p) -> sum([p[i]*(x.^i./factorial(i)) for i in 1:k]))
end

for l in 1:10
    curve_fit(eval(m(l)), x, y)
    ... some code ...
end

I’d appreciate if someone could help me with this.

I think you nearly had it, but tried to make it more complicated than needed. If I get your point, you don’t really need metaprogramming (eval expressions, etc.) Just returning an anonymous function should be fine:

function m(k)
    return (x,p) -> sum([p[i]*(x.^i./factorial(i)) for i in 1:k])
end

for l in 1:10
    curve_fit(m(l), x, y)
    ... some code ...
end
2 Likes

As a new user, I’d also like to point out that use a comprehension with the [ ] isn’t necessary, and you can instead use the generator expression. So instead, you would do sum(p[i]*(x.^i./factorial(i)) for i in 1:k). Notice the brackets were removed. https://docs.julialang.org/en/v1/manual/arrays/#Generator-Expressions-1

With the array comprehension with the brackets, the vector is allocated memory, calculated for each element, then it is summed. With the generated expression, it is calculated and summed without allocating any memory.

4 Likes

@heliosdrm thank you. I tried it, but the curve_fit function form LsqFit.jl can not handle this kind of return type. At least it gives me the following error:

MethodError: no method matching curve_fit(::var"#50#52"{Int64}, ::Array{Int64,1}, ::Array{Float64,1})
Closest candidates are:
  curve_fit(::Any, ::AbstractArray, ::AbstractArray, !Matched::AbstractArray{T,2}, !Matched::Any; kwargs...) where T at /home/yannick/.julia/packages/LsqFit/NjkFI/src/curve_fit.jl:168
  curve_fit(::Any, ::AbstractArray, ::AbstractArray, !Matched::AbstractArray; inplace, kwargs...) at /home/yannick/.julia/packages/LsqFit/NjkFI/src/curve_fit.jl:106
  curve_fit(::Any, ::AbstractArray, ::AbstractArray, !Matched::AbstractArray{T,N} where N, !Matched::AbstractArray; inplace, kwargs...) where T at /home/yannick/.julia/packages/LsqFit/NjkFI/src/curve_fit.jl:137
  ...

Maybe this problem is related to the fact that the curve_fit function expects as first input a function, which returns any Float or Int type, but when I try

ptintln(m(2)([1 2 3], [1 2])) 

an array is returned.

Edit: Never mide.Of cource it should give an array if the x input is an array. But the error still bothers me…

@Daniel_Berge Ahh, quite intresting to know, thanks.

I don’t know the details of LsqFit.jl, but looking at the documentation of curve_fit and the error you cite, I’d say that its primary cause is that curve_fit needs four arguments, and you are only passing three.

Well, this is rather stupid mistake. Thank you for pointing it out.