function create_simple_function()
str = "v -> v[1]^2*v[3]^-1"
expr::Expr = parse(str)
f::Function = eval(expr)
return f
end
@code_warntype(create_simple_function())
Variables:
#self#::#create_simple_function
str::String
expr::Expr
f::F
Body:
begin
str::String = "v -> v[1]^2*v[3]^-1" # line 3:
SSAValue(0) = $(Expr(:invoke, LambdaInfo for #parse#311(::Bool, ::Function, ::String), :(Base.#parse#311), true, :(Main.parse), :(str)))
expr::Expr = (Base.convert)(Main.Expr,SSAValue(0))::Expr # line 4:
SSAValue(1) = (Core.eval)(Core.Main,expr::Expr)::Any
f::F = (Base.convert)(Main.Function,SSAValue(1))::F # line 5:
return f::F
end::F
My question is : why is SSAValue(1) of type Any?
In my working code I have thousands of functions to be created this way (with 1 and 2 replaced by is and js etc) and I found by profiling that this line is taking the most time.
Is this the way I should be creating those functions anyway?
You usually shouldn’t create functions this way. Even if you have to for some reason, you must not create it by parsing a string unless the string is user input. You’ll also get an error on master when you call the function. It’s unclear what you actually want to do so it’s hard to say what’s the right solution for you.
I’m trying to implement Automorphism Groups of Groups. For abelian groups these are given by GL(N,ZZ), so I can get away with matrices; For more general groups I need a generic object/function mapping one generating set to another, e.g. if G = <x,y| some relations> automorphism may be given by prescribing its values on the generators, say (x→x*y, y→x).
If I want to compose two of such automorphisms then – I need to compose those functions.
so If a user gave me input (x→x*y, y→x) I want to create a function (x,y) = v → (v[1]*v[2], v[1]) = (x*y, x)
I gave only a minimal example in the working code this is what I am doing: first generating f1 and f2 then returning the vector of their values. Side-note: f1 needs the whole v;
The thing is – Automorphism Groups are large and I need to generate many of simple functions like those, not a single one.
Now if You look at automorphisms of a group with 10 (or more) generators It contains at least hundreds similar automorphisms (ones comming from multiplication on the left/right by a generator/its inverse) do You have to write all of them by hand as You suggested? I thought: Metaprogramming, i.e. make julia generate code for me.
hence the function in the first post (which is just one of fis) should probably be like
function create_automorphism(i,j)
str = "v -> v[i]*v[j]"
expr::Expr = parse(str)
f::Function = eval(expr)
return f
end
Now, when it should be somehow clear what I want to do, the question remains:
Why is eval ::Any and is this the way to go?
Julia performs type inference based purely upon the types of the variables in your function. In that function, you take a string and evaluate it. That string could contain anything, including run(`rm -rf /`), so it could similarly return anything.
Just return the function directly. This returns a closure and holds on to i and j for you:
julia> function create_automorphism(i,j)
return v->v[i]*v[j]
end
create_automorphism (generic function with 1 method)
julia> f = create_automorphism(2,3)
(::#5) (generic function with 1 method)
julia> f(1:3)
6