Evaluate multi-variable anonymous function for one variable


#1

Hi Julians,

I have an anonymous function f, of several variables x1, x2,…, xn, say for example:
f1 = (x1, x2, x3) = 5x1 + x2^2 + x3^0.25
I would like to create a new function, say g, with g = f(x1,value2, value3), with value2 and value3 are real numbers and x1 should remain as a variable. For example, if value2= 0.1 and value3= 3.0, I should be able to obtain g(x1) = 5x1 + 1.326074. It is similar to substitution in Maple or Matlab.
How would you solve this problem.

Many thanks


#2

You do it, as you would in Matlab, with a closure:

julia> f1 = (x1, x2, x3) -> 5x1 + x2^2 + x3^0.25
(::#3) (generic function with 1 method)

julia> const value1,value2= 4,5 # use const here for performace
(4, 5)
                                                                                                                                                                     
julia> g = x1 -> f1(x1, value1, value2)                                                                                                                                  
(::#7) (generic function with 1 method)                                                                                                                                  

julia> g(5)                                                                                                                                                              
42.49534878122122                                                                                                                                                        

#3

Thank you @mauro3 for the prompt answer. I’m aware of what you said, however, I’m looking for a way to generate the function g (of a single variable) based on an input. g could be a function of x1 or x2, or xi. We don’t know until we know what are the inputs. Say for example we pay an array [value1, x2, value2], in this case, the array has numerical values for x1 and x3, then g would be a function of x2 only. How can we solve this type of problem?


#4

I don’t really understand what you want. Maybe you need to combine above with an if and generate a different closure depending on what inputs you got? Send a code snippet of what you got (please quote you code: PSA: how to quote code with backticks).


#5

I don’t have a code yet; the code is an implementation of a modified Point Estimate Method. Given a function f(x1,x2,…,xn) we want to fix all variables except xi, then evaluate the function at selected points. We repeat this process by leaving one variable and fixing the rest of variables each time. The function is input by the user, for example in the form of an anonymous function.
The process needs to be automatic, given any function f.
Example:
f(x1, x2, x3) = x1^2 + x1*cos(x2) - 5x3

step 1: leave x1 and fix x2 and x3 at 1.5 and 0.8
g1(x1) = f(x1, 1.5, 0.8)
step 2: leave x2 and fix x1 and x3 at 0.75 and 0.8
g2(x2) = f(0.75, x2, 0.8)
step 3: leave x3 and fix x1 and x2 at 0.75 and 1.5
g3(x3) = f(0.75, 1.5, x3)

Hope this clarifies the problem.
Thank you.


#6

Read the link I posted (again) :wink:


#7

As @mauro3 suggested, all you need to do is create a new anonymous function for each of your g_i, where each anonymous function takes only one argument (x_i) and stores the appropriate values of the other arguments to f. A function with some of its arguments already bound to values is a closure and we usually write them in Julia with anonymous functions.

For example, given f(x, y), we can make g1 an anonymous function that only takes x and holds a default value for y:

julia> f(x, y) = x + y
f (generic function with 1 method)

julia> g1 = x -> f(x, 2.0)  # y = 2.0
(::#1) (generic function with 1 method)

julia> g2 = y -> f(1.5, y)  # x = 1.5
(::#3) (generic function with 1 method)

julia> g1(1.5) == g2(2.0) == f(1.5, 2.0)
true

To automate this across all the inputs to some function f, we just need to build up those anonymous functions in a loop.

Here’s one way to do it. I’m using the helpful setindex function from StaticArrays.jl to make this a bit more efficient:

julia> using StaticArrays: setindex

julia> function make_closures(f, default_values...)
         [xi -> f(setindex(default_values, xi, i)...) for i in 1:length(default_values)]
       end
make_closures (generic function with 1 method)

julia> gs = make_closures(f, 0.75, 1.5, 0.8)
3-element Array{##11#13{Int64,#f,Tuple{Float64,Float64,Float64}},1}:
 #11
 #11
 #11

julia> gs[1](1.0) == f(1.0, 1.5, 0.8)
true

julia> gs[2](1.0) == f(0.75, 1.0, 0.8)
true

julia> gs[3](1.0) == f(0.75, 1.5, 1.0)
true

A very nice feature of Julia is that you can do this with essentially no performance penalty. Using BenchmarkTools.jl:

julia> using BenchmarkTools

julia> @btime $(gs[1])(0.75)
  14.931 ns (0 allocations: 0 bytes)

Also, as @mauro3 suggested, it will be easier for us to read your code and help you if you quote it properly


#8

Thank you very much @rdeits and @mauro3 for your kind help, very much appreciated.
I have the code written in Matlab and I’m planning to write it in Julia. I will share the full code with all Julians in this forum. Here is the paper that details the Point Estimate Method I’m implementing: System Reliability Assessment by Method of Moments.