Error on serialize lambda function with closured data - julia

I use code like this:
p = _belineInterpolateGrid( map( p -> sin(norm(p)), grid ), grid )
f = open("/data/test.function", "w")
serialize( f, p )
close(f)
p0 = deserialize( open("/data/test.function", "r") )
where _belineInterpolateGrid is
function _belineInterpolateGrid(PP, Grid)
...
P = Array(Function, N-1, M-1);
...
poly = (x,y) -> begin
i_x, i_y = i(x, y);
return P[i_x, i_y](x, y);
end
return poly
And now, since some of v0.4, a have an error:
ERROR: MethodError: `convert` has no method matching
convert(::Type{LambdaStaticData}, ::Array{Any,1})
This may have arisen from a call to the constructor LambdaStaticData(...),
since type constructors fall back to convert methods.
Closest candidates are:
call{T}(::Type{T}, ::Any)
convert{T}(::Type{T}, ::T)
...
in deserialize at serialize.jl:435
Why It's happend? Is it bug and how to fix it?

This looks like a bug in Julia to me, and it looks like it has been fixed as of v0.4.6. Try upgrading to that version or newer and see if the problem persists.

You're returning a lambda, that's why. Can't tell if it's a bug (you can serialize a lambda but you can't deserialize it?).
You can avoid this by defining your "get interpolation at x,y" as a type:
import Base: getindex
type MyPoly
thepoly
end
function getindex(p::MyPoly, x::Int, y::Int)
p.thepoly[x+5*y]
end
function getindex(p::MyPoly, I...)
p.thepoly[I...]
end
function call(p::MyPoly, v)
#collect helps keep eltype(ans) == Int
powered_v = map( i->v^i, collect(
take(countfrom(),size(p.thepoly,1))))
powered_v.*p.thepoly
end
p=MyPoly(collect(1:10))
println(p[1])
f = open("serializedpoly", "w")
serialize( f, p)
close(f)
p0 = deserialize( open("serializedpoly", "r"))
println(p[1,1])
v=call(p, 4) #evaluate poly on 4
EDIT: added extension for call

Related

LoadError: MethodError: "Method too new to be called from this world context." in Julia

Can someone explain in simple terms why this error occurs and how it can be avoided except not placing the code in main in a function?
Please refer to question Improving the performance of SymPy function generated from string in Julia for the function string_to_func.
Works:
using SymPy
function string_to_func(function_string)
func_lambdify = lambdify(SymPy.sympify(function_string), invoke_latest=false)
#eval func(x, y, z) = ($func_lambdify)(x, y, z)
return Nothing
end
function_string = "x + y + z"
string_to_func(function_string)
result = func(1, 2, 3)
Throws Error:
using SymPy
function string_to_func(function_string)
expr = lambdify(SymPy.sympify(function_string), invoke_latest=false)
#eval func(x, y, z) = ($expr)(x, y, z)
return Nothing
end
function main()
function_string = "x + y + z"
string_to_func(function_string)
result = func(1, 2, 3)
end
main()
Anonymized Error Message:
ERROR: LoadError: MethodError: no method matching func(::Int64, ::Int64, ::Int64)
The applicable method may be too new: running in world age 29676, while current world is 29678.
Closest candidates are:
func(::Any, ::Any, ::Any) at path_to_folder\test.jl:5 (method too new to be called from this world context.)
Stacktrace:
[1] main()
# Main path_to_folder\test.jl:12
[2] top-level scope
# path_to_folder\test.jl:15
in expression starting at path_to_folder\test.jl:15
You need to invoke func using Base.invokelatest, i.e.
function main()
function_string = "x + y + z"
string_to_func(function_string)
result = Base.invokelatest(func, 1, 2, 3)
end
See the manual for further details about world age and why invokelatest is needed here.
I should also mention GeneratedFunctions.jl that can avoid some of the overhead associated with invokelatest, although it has it is own caveats since its somewhat of a hack.

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

Zygote.Hessian: Mutating arrays is not supported

I'm trying to calculate the laplacian of neural network. This is my code:
using Flux
using Zygote
model = Chain(Dense(2,5,sigmoid), Dense(5,1))
function laplace(x)
a, b = size(x)
Δ = Zygote.Buffer(zeros(b))
deriv2 = sum(Diagonal(ones(a*b)).*Zygote.hessian(v -> sum(model(v)), x), dims=1)
for i=1:b
for j=1:a
Δ[i] += deriv2[(i-1)*a+j]
end
end
return copy(Δ)
end
gradient(x -> sum(laplace(x)), rand(2,5))
I'll see the same error even if I define a function like this:
function function(x)
return sum(Zygote.hessian(v -> sum(model(v)), x))
end
gradient(x -> function(x), rand(2,5))
Why do I get this error?

Iterating over different functions with different number of parameters in Julia

I'm trying to run a loop over different functions with different number of arguments. The variables are created at runtime inside the loop, and I want to use eval at each iteration to instantiate a Struct using the variable :symbol. However, I can't do this since eval only works in the global scope. This is the MWE for the case that works:
function f1(x); return x; end
function f2(x1,x2); return x1+x2; end
handles = [f1,f2]
args =[:(x1),:(x1,x2)]
x1 = 1; x2 = 1;
for (i,f) in enumerate(handles)
params = eval(args[i])
#show f(params...)
end
f(params...) = 1
f(params...) = 2
However, if I move the variable definitions inside the loop, which is what I actually want, it doesn't work after restarting Julia to clear the workspace.
function f1(x); return x; end
function f2(x1,x2); return x1+x2; end
handles = [f1,f2]
args =[:(x1),:(x1,x2)]
for (i,f) in enumerate(handles)
x1 = 1; x2 = 1;
params = eval(args[i])
#show f(params...)
end
ERROR: UndefVarError: x1 not defined
I've tried several of the answers, such as this one, but I can't seem to make it work. I could write a custom dispatch function that takes[x1,x2] and calls f1 or f2 with the correct arguments. But still, is there any way to do this with eval or with an alternative elegant solution?
EDIT: here are more details as to what I'm trying to do in my code. I have a config struct for each algorithm, and in this I want to define beforehand the arguments it takes
KMF_config = AlgConfig(
name = "KMF",
constructor = KMC.KMF,
parameters = :(mu,N,L,p),
fit = KMC.fit!)
MF_config = AlgConfig(
name = "MF",
constructor = KMC.MF,
parameters = :(mu,N,L),
fit = KMC.fit!)
alg_config_list = [KMF_config, MF_config]
for (i,alg_config) in enumerate(alg_config_list)
mu,N,L,p,A,B,C,D,data = gen_vars() #this returns a bunch of variables that are used in different algorithms
method = alg_config.constructor(eval(method.parameters)...)
method.fit(data)
end
One possible solution is to have a function take all the variables and method, and return a tuple with a subset of variables according to method.name. But I'm not sure if it's the best way to do it.
Here's an approach using multiple dispatch rather than eval:
run_a(x, y) = x + 10*y
run_b(x, y, z) = x + 10*y + 100*z
extract(p, ::typeof(run_a)) = (p.x, p.y)
extract(p, ::typeof(run_b)) = (p.x, p.y, p.z)
genvars() = (x=1, y=2, z=3)
function doall()
todo = [
run_a,
run_b,
]
for runalg in todo
v = genvars()
p = extract(v, runalg)
#show runalg(p...)
end
end
In your example you would replace run_a and run_b with KMC.KMF and KMC.MF.
Edit: Cleaned up example to avoid structs that don't exist in your example.

How to transform a custom datatype to arrays of arrays

I'm new to Julia and I have some difficulties with the programming with types approach.
I wanted to load a 3D mesh from a file to practice and I have made some custom types to store it.
Here are my types:
struct Vertex
x::Number
y::Number
z::Number
Vertex(x::Number, y::Number, z::Number) = new(x, y, z)
Vertex(t::Tuple{Number, Number, Number}) = new(t[1], t[2], t[3])
Vertex(x::Number, y::Number) = new(x, y, 0)
Vertex(t::Tuple{Number, Number}) = new(t[1], t[2], 0)
Vertex(x::Number) = new(x, 0, 0)
Vertex(t::Tuple{Number}) = new(t[1], 0, 0)
Vertex() = new(0, 0, 0)
Vertex(t::Tuple{}) = new(0, 0, 0)
end
struct Mesh
t::Vector{Vertex} # List of triangles
f::Vector{Vertex} # List of faces
n::Vector{Vertex} # List of normals
Mesh(t::Vertex, f::Vertex) = new([t], [f], [])
Mesh(t::Vector{Vertex}, f::Vector{Vertex}, n::Vector{Vertex}) = new(t, f, n)
Mesh(t::Vector{Vertex}, f::Vector{Vertex}, n::Vector) = new(t, f, n)
Mesh(t::Vector, f::Vector, n::Vector) = new(t, f, n)
#Mesh(t::Triangle) = new([t], [])
#Mesh(t::Vector{Triangle}) = new(t, [])
end
I can effectively load a mesh in my Mesh type.
Now, I would like to plot it using the method plot_trisurf from PyPlot. However, this method expect an array of arrays and I'm not sure my way of doing it is the right way:
function plotMesh(M)
Xv = map(e -> e.x, M.t[:])
Yv = map(e -> e.x, M.t[:])
Zv = map(e -> e.x, M.t[:])
Fv = map(e -> (e.x, e.y, e.z), M.f[:])
plot_trisurf(Xv, Yv, Zv, triangles=Fv, alpha=1)
gca()[:projection] = "3d"
end
Q:
The Xv, Yv, Zv doesn't feel right at the moment,
and the Fv do not work at all. [Corrected -> see Edit]
What it the best way of doing this?
Is my type design correct? or should I change it to something more suitable?
Thanks
[edit]
After some more tests I finally managed to make it work, however I'm still not sure if it is the best way to do things in Julia nor if my type system is a good one.
function plotMesh(M::Mesh)
Xv = map(e -> e.x, M.t[:])
Yv = map(e -> e.y, M.t[:])
Zv = map(e -> e.z, M.t[:])
Fv = map(e -> [Int(e.x)-1, Int(e.y)-1, Int(e.z)-1], M.f[:])
print(size(Xv))
print(size(Fv))
plot_trisurf(Xv, Yv, Zv, triangles=Fv)
gca()[:projection] = "3d"
end
First 3D plot in Julia
[edit]
The vertices and normals are (in general) floats and the faces are integers.
The object I'm using is bunny.obj
and my code for loading the object in the structures is:
function read_obj(filename::String)
v = []
f = []
n = []
tof(x) = parse(Float64, x)
open(filename) do file
for line in eachline(file)
l = split(line, ' ')
if l[1] ∈ ["v", "f", "n"]
values = (tof(l[2]), tof(l[3]), tof(l[4]))
if l[1] == "v"
push!(v, Vertex(values))
elseif l[1] == "f"
faces = (Int(values[1]), Int(values[2]), Int(values[3]))
push!(f, Vertex(faces))
elseif l[1] == "n"
push!(n, Vertex(values))
end
end
end
end
return Mesh(v, f, n)
end
My way of loading the object is surely not the best way of doing it. If you have any material to improve my skills feel free to share :)
First I would change the definition of Vertex like this (it seems below you require entries to be integers, if not, you can change Integer to Number)
struct Vertex{T<:Integer}
x::T
y::T
z::T
end
Vertex(x::T=0, y::T=zero(T)) where {T<:Integer} = Vertex(x,y,zero(T))
Vertex(t::Tuple) = Vertex(t...)
Next in Mesh you can use StructArrays.jl package like this (this way you can easily access fields of Vertex as vectors):
using StructArrays
struct Mesh{S<:StructArray, T}
t::S
f::S
n::S
function Mesh(t::Vector{T}, f::Vector{T}, n::Vector{T}) where {T<:Vertex}
st, sf, sn = StructArray(t), StructArray(f), StructArray(n)
new{typeof(st), T}(st, sf, sn)
end
end
Mesh(t::T, f::T) where {T<:Vertex} = Mesh([t], [f], T[])
now you can define the plotting function for example as:
function plotMesh(M::Mesh{S, T}) where {S,T}
Fv = eachrow([M.f.x M.f.y M.f.z] .- one(T))
print(size(M.t.x))
print(size(Fv))
plot_trisurf(M.t.x, M.t.y, M.t.z, triangles=Fv)
gca()[:projection] = "3d"
end
Note 1: All codes make sure that all the structures operate on concrete types so that the code will be faster than using abstract types (like Number). Also I make sure that all entries have the same type.
Note 2: I have written this from my head as you did not provide data to test the code against (so please let me know if anything fails in this code). Strictly speaking you do not have to use StructArrays.jl to achieve the goal, but I hope that you will agree that using them gives you a more readable code.

Resources