Julia - generate an array of functions programmatically - julia

I want to generate an array of functions programmatically, with a loop so that each successive function depends on the previous.
For example in pseudo-code:
f_array = [f1, f2, f3]
with:
f1(x) = x
f2(x) = 3 * f1(x)
f3(x) = 3 * f2(x)
so that I could call:
f_array[3](x)
and get the result of f3(x)
Here is what I have tried:
# create simple function just to initialize
f(x)=x
# initialize array of functions
N = 3
f_array = fill(f, N)
# now we update each function
for i in 2:N
f_array[i] = (f(x)= 3 * f_array[i-1](x))
end
I get an error:
ERROR: MethodError: Cannot convert an object of type getfield(Main,
Symbol("#f#15")){Int64} to an object of type typeof(f)
I cannot find a solution at the moment. Any help would be appreciated.

When you use fill with f it sets expected type for the elements of f_array to f, in the code below I am switching to abstract type to make it possible to have any function in the array
# create simple function just to initialize
f(x)=x
# initialize array of functions
N = 3
f_array = Array{Function}(undef, N);
f_array[1] = f;
# now we update each function
for i in 2:N
f_array[i] = x -> 3 * f_array[i-1](x)
end
print(f_array[3](2))
which produces a value of 18

In the mean time, I also found a way using metaprogramming. I post this here as it could be useful for others:
f1(x) = x
for i in 2:N
prog = "f$i(x) = 3 * f$(i-1)(x)"
exp = Meta.parse(prog)
eval(exp)
end
f3(2)
# 18

I'd write Yegor's answer as
f_array = Function[identity]
for i in 2:3
push!(f_array, x -> 3f_array[i-1](x))
end
But more importantly, this is a well known pattern: iterated function application. And it is already implemented, not in Base, but for example in IterTools.jl, by which you should be able to write:
f_array(start, N) = collect(Iterators.take(iterated(x -> 3x, start), N))
(I didn't test this, though.)

Related

Acess methods for struct initialisation

I would like to do something like this:
Base.#kwdef mutable struct Setup
# physics
lx = 20.0
dc = 1.0
n = 4
# inital condition
ic(x) = exp(-(x-lx/4)^2)
# numerics
nx = 200
nvis = 50
# derived numerics
dx = lx/nx
dt = dx^2/dc/10
nt = nx^2 ÷ 5
# arrays
xc = LinRange(dx/2,lx-dx/2,nx)
C0 = ic.(xc)
C = copy(C)
q = zeros(nx-1)
# collections for easy use
dgl_params=[dc,n]
end
The problem here is that it says ic was undefined. Makes sense, because ic is not in the global scope.
Then I tried writing an outside constructor instead (I am not writing an inside constructor as that would overwrite the default constructor).
Base.#kwdef mutable struct Setup
# physics
lx = 20.0
dc = 1.0
n = 4
# inital condition
ic(x) = exp(-(x-lx/4)^2)
# numerics
nx = 200
nvis = 50
# derived numerics
dx = lx/nx
dt = dx^2/dc/10
nt = nx^2 ÷ 5
# arrays
xc = LinRange(dx/2,lx-dx/2,nx)
# C0 = ic.(xc)
C0
C = copy(C)
q = zeros(nx-1)
# collections for easy use
dgl_params=[dc,n]
end
function Setup()
Setup(Setup.ic(Setup.xc))
end
Setup()
But now it says DataType has no field ic which of course makes sense, I want the ic of the object itself. However there appears to be no selfor this keyword in julia.
Strangely enough the above seems to work fine with dx or dt which are also depending on other variables
Normally the design is to have multiple dispatch and functions outside of the object
When creating structs always provide the datatype of elements
For this large structs usually you will find out that using Parameters package will be more convenient when later debugging
The easiest way to circumvent the limitation is to have a lambda function in a field such as (this is however not the recommended Julia style):
#with_kw mutable struct Setup
lx::Float64 = 20.0
ic::Function = x -> lx * x
end
This can be now used as:
julia> s = Setup(lx=30)
Setup
lx: Float64 30.0
ic: #10 (function of type var"#10#14"{Int64})
julia> s.ic(10)
300
Actually, it is not in the design to have what in Java or C++ you would call "member functions". Part of this is Julia's will to benefit from the multiple dispatch programming paradigm. In Julia, mutables are pointers, so you pass them directly to a function, e.g.
function ic(setup::Setup, x)
return exp(-(x-setup.lx/4)^2)
end
That said, there is still a way to have more Java-esque classes, though not super recommended. Check this thread and, particularly, the answered marked as solution, given by one of Julia's authors themself.
Okay, I found the solution.
This does not work, because there are no methods in julia:
Base.#kwdef mutable struct S
n = 5
m
f(x) = x + 100
A = f.(randn(n,m))
end
s = S(m=5) # ERROR: UndefVarError: f not defined
s.A
s.f(5)
But this does work, because here f is a variable and not a function
Base.#kwdef mutable struct S
n = 5
m
f= x-> x + 100
A = f.(randn(n,m))
end
s = S(m=5)
s.A
s.f(5)

Updating a list of StaticArrays

Suppose I have this function, implemented without StaticArrays
function example_svector_bad(G)
vector_list = [ randn(G) for q in 1:1000]
for i in size(vector_list)
for g in 1:G
vector_list[i][g] = vector_list[i][g] * g
end
end
return vector_list
end
I'm hoping to implement it using StaticArrays for speed gains. However, I don't know how to do it without losing the flexibility of specifying G. For example, I could do
function example_svector()
vector_list = [#SVector randn(3) for q in 1:1000]
for i in size(vector_list)
vector_list[i] = SVector(vector_list[i][1] * 1, vector_list[i][1] * 2,
vector_list[i][1] * 3)
end
return vector_list
end
if I knew that G = 3 and I had to write out SVector(vector_list[i][1] * 1, vector_list[i][1] * 2, vector_list[i][1] * 3).
Is there a way to implement this for any arbitrary number of G?
The size of a static vector or array must be known at the compile time.
At the compile time only types are known (rather than values).
Hence your function could look like this:
function myRandVec(::Val{G}) where G
SVector{G}(rand(G))
end
Note that G is passed as type rather than as value and hence can be used to create a static vector.
This function could be used as:
julia> myRandVec(Val{2}())
2-element SVector{2, Float64} with indices SOneTo(2):
0.7618992223709563
0.5979657793050613
Firstly, there is a mistake in how you are indexing vector_list, where you do
for i in size(vector_list)
Let's see what that does:
julia> x = 1:10;
julia> size(x)
(10,)
The size of x is its length in each dimension, for a vector that is just (10,) since it has only one dimension. Let's try iterating:
julia> for i in size(x)
println(i)
end
10
It just prints out the number 10.
You probably meant
for i in 1:length(vector_list)
but it's better to write
for i in eachindex(vector_list)
since it is more general and safer.
As for your actual question, you can use StaticArrays.SOneTo which provides a static version of [1,2,3]:
function example_svector()
vector_list = [#SVector randn(3) for q in 1:1000]
N = length(eltype(vector_list))
c = SOneTo(N)
for i in eachindex(vector_list)
vector_list[i] = vector_list[i] .* c
end
return vector_list
end

Julia JuMP making sure nonlinear objective function has correct function signatures so that autodifferentiate works properly?

so I wrote a minimum example to show what I'm trying to do. Basically I want to solve a optimization problem with multiple variables. When I try to do this in JuMP I was having issues with my function obj not being able to take a forwardDiff object.
I looked here: and it seemed to do with the function signature :Restricting function signatures while using ForwardDiff in Julia . I did this in my obj function, and for insurance did it in my sub-function as well, but I still get the error
LoadError: MethodError: no method matching Float64(::ForwardDiff.Dual{ForwardDiff.Tag{JuMP.var"#110#112"{typeof(my_fun)},Float64},Float64,2})
Closest candidates are:
Float64(::Real, ::RoundingMode) where T<:AbstractFloat at rounding.jl:200
Float64(::T) where T<:Number at boot.jl:715
Float64(::Int8) at float.jl:60
This still does not work. I feel like I have the bulk of the code correct, just some weird of type thing going on that I have to clear up so autodifferentiate works...
Any suggestions?
using JuMP
using Ipopt
using LinearAlgebra
function obj(x::Array{<:Real,1})
println(x)
x1 = x[1]
x2 = x[2]
eye= Matrix{Float64}(I, 4, 4)
obj_val = tr(eye-kron(mat_fun(x1),mat_fun(x2)))
println(obj_val)
return obj_val
end
function mat_fun(var::T) where {T<:Real}
eye= Matrix{Float64}(I, 2, 2)
eye[2,2]=var
return eye
end
m = Model(Ipopt.Optimizer)
my_fun(x...) = obj(collect(x))
#variable(m, 0<=x[1:2]<=2.0*pi)
register(m, :my_fun, 2, my_fun; autodiff = true)
#NLobjective(m, Min, my_fun(x...))
optimize!(m)
# retrieve the objective value, corresponding x values and the status
println(JuMP.value.(x))
println(JuMP.objective_value(m))
println(JuMP.termination_status(m))
Use instead
function obj(x::Vector{T}) where {T}
println(x)
x1 = x[1]
x2 = x[2]
eye= Matrix{T}(I, 4, 4)
obj_val = tr(eye-kron(mat_fun(x1),mat_fun(x2)))
println(obj_val)
return obj_val
end
function mat_fun(var::T) where {T}
eye= Matrix{T}(I, 2, 2)
eye[2,2]=var
return eye
end
Essentially, anywhere you see Float64, replace it by the type in the incoming argument.
I found the problem:
in my mat_fun the type of the return had to be "Real" in order for it to propgate through. Before it was Float64, which was not consistent with the fact I guess all types have to be Real with the autodifferentiate. Even though a Float64 is clearly Real, it looks like the inheritence isn't perserved i.e you have to make sure everything that is returned and inputed are type Real.
using JuMP
using Ipopt
using LinearAlgebra
function obj(x::AbstractVector{T}) where {T<:Real}
println(x)
x1 = x[1]
x2 = x[2]
eye= Matrix{Float64}(I, 4, 4)
obj_val = tr(eye-kron(mat_fun(x1),mat_fun(x2)))
#println(obj_val)
return obj_val
end
function mat_fun(var::T) where {T<:Real}
eye= zeros(Real,(2,2))
eye[2,2]=var
return eye
end
m = Model(Ipopt.Optimizer)
my_fun(x...) = obj(collect(x))
#variable(m, 0<=x[1:2]<=2.0*pi)
register(m, :my_fun, 2, my_fun; autodiff = true)
#NLobjective(m, Min, my_fun(x...))
optimize!(m)
# retrieve the objective value, corresponding x values and the status
println(JuMP.value.(x))
println(JuMP.objective_value(m))
println(JuMP.termination_status(m))

Is it possible to convert an Array{Num,1} to Array{Float64,1} in Julia?

I have the following function that uses symbolics in Julia. Everything works fine until the moment of plotting
using Distributions
using Plots
using Symbolics
using SymbolicUtils
function BinomialMeasure(iter::Int64, p::Float64, current_level = nothing)
#variables m0 m1
if current_level == nothing
current_level = [1]
end
next_level = []
for item in current_level
append!(next_level, m0*item)
append!(next_level, m1*item)
end
If iter != 0
current_level = next_level
return BinomialMeasure(iter - 1, p , current_level)
else
return [substitute(i, Dict([m0 => p, m1 => 1 - p])) for i in next_level]
end
end
y = BinomialMeasure(10, 0.4)
x = [( i + 1 ) / length(y) for i = 1:length(y) ]
append!(x, 0)
append!(y,0)
plot(x,y)
Then it returns the following:
MethodError: no method matching AbstractFloat(::Num)
Closest candidates are:
AbstractFloat(::Real, !Matched::RoundingMode) where T<:AbstractFloat at rounding.jl:200
AbstractFloat(::T) where T<:Number at boot.jl:716
AbstractFloat(!Matched::Bool) at float.jl:258
y is an Array{Num,1} and x is an Array{Float64,1}.
I tried map(float, y), convert(float,y) and float(y), but I think it not possible to convert a type Num to a Float64 or at least I don't know how to do it.
you can access the field val without using string and parse
y_val = [i.val for i in y]
this will of course have way better performance than parsing a string

How do I evaluate the function in only one of its variables in Scilab

How do I evaluate the function in only one of its variables, that is, I hope to obtain another function after evaluating the function. I have the following piece of code.
deff ('[F] = fun (x, y)', 'F = x ^ 2-3 * y ^ 2 + x * y ^ 3');
fun (4, y)
I hope to get 16-3y ^ 2 + 4y ^ 3
If what you want to do is to write x = f(4,y), and later just do x(2) to get -36, that is called partial application:
Intuitively, partial function application says "if you fix the first arguments of the function, you get a function of the remaining arguments".
This is a very useful feature, and very common Functional Programming Languages, such as Haskell, but even JS and Python now are able to do it. It is also possible to do this in MATLAB and GNU/Octave using anonymous functions (see this answer). In Scilab, however, this feature is not available.
Workround
Nonetheless, Scilab itself uses a workarounds to carry a function with its arguments without fully evaluating. You see this being used in ode(), fsolve(), optim(), and others:
Create a list containing the function and the arguments to partial evaluation: list(f,arg1,arg2,...,argn)
Use another function to evaluate such list and the last argument: evalPartList(list(...),last_arg)
The implementation of evalPartList() can be something like this:
function y = evalPartList(fList,last_arg)
//fList: list in which the first element is a function
//last_arg: last argument to be applied to the function
func = fList(1); //extract function from the list
y = func(fList(2:$),last_arg); //each element of the list, from second
//to last, becomes an argument
endfunction
You can test it on Scilab's console:
--> deff ('[F] = fun (x, y)', 'F = x ^ 2-3 * y ^ 2 + x * y ^ 3');
--> x = list(fun,4)
x =
x(1)
[F]= x(1)(x,y)
x(2)
4.
--> evalPartList(x,2)
ans =
36.
This is a very simple implementation for evalPartList(), and you have to be careful not to exceed or be short on the number of arguments.
In the way you're asking, you can't.
What you're looking is called symbolic (or formal) computational mathematics, because you don't pass actual numerical values to functions.
Scilab is numerical software so it can't do such thing. But there is a toolbox scimax (installation guide) that rely on a the free formal software wxmaxima.
BUT
An ugly, stupid but still sort of working solution is to takes advantages of strings :
function F = fun (x, y) // Here we define a function that may return a constant or string depending on the input
fmt = '%10.3E'
if (type(x)==type('')) & (type(y)==type(0)) // x is string is
ys = msprintf(fmt,y)
F = x+'^2 - 3*'+ys+'^2 + '+x+'*'+ys+'^3'
end
if (type(y)==type('')) & (type(x)==type(0)) // y is string so is F
xs = msprintf(fmt,x)
F = xs+'^2 - 3*'+y+'^2 + '+xs+'*'+y+'^3'
end
if (type(y)==type('')) & (type(x)==type('')) // x&y are strings so is F
F = x+'^2 - 3*'+y+'^2 + '+x+'*'+y+'^3'
end
if (type(y)==type(0)) & (type(x)==type(0)) // x&y are constant so is F
F = x^2 - 3*y^2 + x*y^3
end
endfunction
// Then we can use this 'symbolic' function
deff('F2 = fun2(y)',' F2 = '+fun(4,'y'))
F2=fun2(2) // does compute fun(4,2)
disp(F2)

Resources