Julia: inject code into function - macros

I would like to inject code into a function. For concreteness, consider a simple simulater:
function simulation(A, x)
for t in 1:1000
z = randn(3)
x = A*x + z
end
end
Sometimes I would like to record the values of x every ten time-steps, sometimes the values of z every 20 time-steps, and sometimes I don't want to record any values. I could, of course, put some flags as arguments to the function, and have some if-else statements. But I would like to rather keep the simulation code clean, and only inject a piece of code like
if t%10 == 0
append!(rec_z, z)
end
into particular places of the function whenever I need it. For that, I'd like to write a macro such that monitoring a particular value becomes
#monitor(:z, 10)
simulation(A, x)
Is that possible with Julia's Metaprogramming capabilities?

No, you cannot use metaprogramming to inject code into an already-written function. Metaprogramming can only do things that you could directly write yourself at precisely the location where the macro itself is written. That means that a statement like:
#monitor(:z, 10); simulation(A, x)
cannot even modify the simulation(A, x) function call. It can only expand out to some normal Julia code that runs before simulation is called. You could, perhaps, include the simulation function call as an argument to the macro, e.g., #monitor(:z, 10, simulation(A, x)), but now all the macro can do is change the function call itself. It still cannot "go back" and add new code to a function that was already written.
You could, however, carefully and meticulously craft a macro that takes the function definition body and modifies it to add your debug code, e.g.,
#monitor(:z, 10, function simulation(A, x)
for t in 1:1000
# ...
end
end)
But now you must write code in the macro that traverses the code in the function body, and injects your debug statement at the correct place. This is not an easy task. And it's even harder to write in a robust manner that wouldn't break the moment you modified your actual simulation code.
Traversing code and inserting it is a much easier task for you to do yourself with an editor. A common idiom for debugging statements is to use a one-liner, like this:
const debug = false
function simulation (A, x)
for t in 1:1000
z = rand(3)
x = A*x + z
debug && t%10==0 && append!(rec_z, z)
end
end
What's really cool here is that by marking debug as constant, Julia is able to completely optimize away the debugging code when it's false — it doesn't even appear in the generated code! So there is no overhead when you're not debugging. It does mean, however, that you have to restart Julia (or reload the module it's in) for you to change the debug flag. Even when debug isn't marked as const, I cannot measure any overhead for this simple loop. And chances are, your loop will be more complicated than this one. So don't worry about performance here until you actually double-check that it's having an effect.

You might be interested in this which i just whipped up. It doesn't QUITE do what you are doing, but it's close. Generally safe and consistent places to add code are the beginning and end of code blocks. These macros allow you to inject some code in those location (and even pass code parameters!)
Should be useful for say toggle-able input checking.
#cleaninject.jl
#cleanly injects some code into the AST of a function.
function code_to_inject()
println("this code is injected")
end
function code_to_inject(a,b)
println("injected code handles $a and $b")
end
macro inject_code_prepend(f)
#make sure this macro precedes a function definition.
isa(f, Expr) || error("checkable macro must precede a function definition")
(f.head == :function) || error("checkable macro must precede a function definition")
#be lazy and let the parser do the hard work.
b2 = parse("code_to_inject()")
#inject the generated code into the AST.
unshift!(f.args[2].args, b2)
#return the escaped function to the parser so that it generates the new function.
return Expr(:escape, f)
end
macro inject_code_append(f)
#make sure this macro precedes a function definition.
isa(f, Expr) || error("checkable macro must precede a function definition")
(f.head == :function) || error("checkable macro must precede a function definition")
#be lazy and let the parser do the hard work.
b2 = parse("code_to_inject()")
#inject the generated code into the AST.
push!(f.args[2].args, b2)
#return the escaped function to the parser so that it generates the new function.
return Expr(:escape, f)
end
macro inject_code_with_args(f)
#make sure this macro precedes a function definition.
isa(f, Expr) || error("checkable macro must precede a function definition")
(f.head == :function) || error("checkable macro must precede a function definition")
#be lazy and let the parser do the hard work.
b2 = parse(string("code_to_inject(", join(f.args[1].args[2:end], ","), ")"))
#inject the generated code into the AST.
unshift!(f.args[2].args, b2)
#return the escaped function to the parser so that it generates the new function.
return Expr(:escape, f)
end
################################################################################
# RESULTS
#=
julia> #inject_code_prepend function p()
println("victim function")
end
p (generic function with 1 method)
julia> p()
this code is injected
victim function
julia> #inject_code_append function p()
println("victim function")
end
p (generic function with 1 method)
julia> p()
victim function
this code is injected
julia> #inject_code_with_args function p(a, b)
println("victim called with $a and $b")
end
p (generic function with 2 methods)
julia> p(1, 2)
injected code handles 1 and 2
victim called with 1 and 2
=#

Related

Calling macro from within generated function in Julia

I have been messing around with generated functions in Julia, and have come to a weird problem I do not understand fully: My final goal would involve calling a macro (more specifically #tullio) from within a generated function (to perform some tensor contractions that depend on the input tensors). But I have been having problems, which I narrowed down to calling the macro from within the generated function.
To illustrate the problem, let's consider a very simple example that also fails:
macro my_add(a,b)
return :($a + $b)
end
function add_one_expr(x::T) where T
y = one(T)
return :( #my_add($x,$y) )
end
#generated function add_one_gen(x::T) where T
y = one(T)
return :( #my_add($x,$y) )
end
With these declarations, I find that eval(add_one_expr(2.0)) works just as expected and returns and expression
:(#my_add 2.0 1.0)
which correctly evaluates to 3.0.
However evaluating add_one_gen(2.0) returns the following error:
MethodError: no method matching +(::Type{Float64}, ::Float64)
Doing some research, I have found that #generated actually produces two codes, and in one only the types of the variables can be used. I think this is what is happening here, but I do not understand what is happening at all. It must be some weird interaction between macros and generated functions.
Can someone explain and/or propose a solution? Thank you!
I find it helpful to think of generated functions as having two components: the body and any generated code (the stuff inside a quote..end). The body is evaluated at compile time, and doesn't "know" the values, only the types. So for a generated function taking x::T as an argument, any references to x in the body will actually point to the type T. This can be very confusing. To make things clearer, I recommend the body only refer to types, never to values.
Here's a little example:
julia> #generated function show_val_and_type(x::T) where {T}
quote
println("x is ", x)
println("\$x is ", $x)
println("T is ", T)
println("\$T is ", $T)
end
end
show_val_and_type
julia> show_val_and_type(3)
x is 3
$x is Int64
T is Int64
$T is Int64
The interpolated $x means "take the x from the body (which refers to T) and splice it in.
If you follow the approach of never referring to values in the body, you can test generated functions by removing the #generated, like this:
julia> function add_one_gen(x::T) where T
y = one(T)
quote
#my_add(x,$y)
end
end
add_one_gen
julia> add_one_gen(3)
quote
#= REPL[42]:4 =#
#= REPL[42]:4 =# #my_add x 1
end
That looks reasonable, but when we test it we get
julia> add_one_gen(3)
ERROR: UndefVarError: x not defined
Stacktrace:
[1] macro expansion
# ./REPL[48]:4 [inlined]
[2] add_one_gen(x::Int64)
# Main ./REPL[48]:1
[3] top-level scope
# REPL[49]:1
So let's see what the macro gives us
julia> #macroexpand #my_add x 1
:(Main.x + 1)
It's pointing to Main.x, which doesn't exist. The macro is being too eager, and we need to delay its evaluation. The standard way to do this is with esc. So finally, this works:
julia> macro my_add(a,b)
return :($(esc(a)) + $(esc(b)))
end
#my_add
julia> #generated function add_one_gen(x::T) where T
y = one(T)
quote
#my_add(x,$y)
end
end
add_one_gen
julia> add_one_gen(3)
4

Can Julia macros be used to generate code based on specific function implementation?

I am fairly new to Julia and I am learning about metaprogramming.
I would like to write a macro that receive in input a function and returns another function based on the implementation details of its input.
For example given:
function f(x)
x + 100
end
function g(x)
f(x)*x
end
function h(x)
g(x)-0.5*f(x)
end
I would like to write a macro that returns something like that:
function h_traced(x)
f = x + 100
println("loc 1 x: ", x)
g = f * x
println("loc 2 x: ", x)
res = g - 0.5 * f
println("loc 3 x: ", x)
Now both code_lowered and code_typed seems to give me back the AST in the form of CodeInfo, however when I try to use it programmatically in my macro I get empty object.
macro myExpand(f)
body = code_lowered(f)
println("myExpand Body lenght: ",length(body))
end
called like this
#myExpand :(h)
however the same call outside the macro works ok.
code_lowered(h)
At last even the following return an empty CodeInfo.
macro myExpand(f)
body = code_lowered(Symbol("h"))
println("myExpand Body lenght: ",length(body))
end
This might be incredible trivial but I could not work out myseld why the h symbol does not resolve to the function defined. Am I missing something about the scope of symbols?
I find it useful to think about macros as a way to transform an input syntax into an output syntax.
So you could very well define a macro #my_macro such that
#my_macro function h(x)
g(x)-0.5*f(x)
end
would expand to something like
function h_traced(x)
println("entering function: x=", x)
g(x)-0.5*f(x)
end
But to such a macro, h is merely a name, an identifier (technically, a Symbol) that can be transformed into h_traced. h is not the function that is bound to this name (in the same way as x = 2 involves binding a name x, to an integer value 2, but x is not 2; x is merely a name that can be used to refer to 2). In contrast to this, when you call code_lowered(h), h gets evaluated first, and code_lowered is passed its value (which is a function) as argument.
Back to our macro: expanding to an expression that involves the definition of g and f goes way further than mere syntax transformations: we're leaving the purely syntactic domain, since such a transformation would need to "understand" that these are functions, look up their definitions and so on.
You are right to think about code_lowered and friends: this is IMO the adequate level of abstraction for what you're trying to achieve. You should probably look into tools like Cassette.jl or IRTools.jl. That being said, if you're still relatively new to Julia, you might want to get a bit more used to the language before delving too deeply into such topics.
You don't need a macro, you need a generated function. They can not only return code (Expr), but also IR (lowered code). Usually, for this kind of thing, people use Base.uncompressed_ast, not code_lowered. Both Cassette and IRTools simplify the implementation for you, in different ways.
The basic idea is:
Have a generated function that takes a function and its arguments
In that function, get the IR of that function, and modify it to your purposes
Return the new IR from the generated function. This will then be compiled and called on the original arguments.
A short demonstration with IRTools:
julia> IRTools.#dynamo function traced(args...)
ir = IRTools.IR(args...)
p = IRTools.Pipe(ir)
for (v, stmt) in p
IRTools.insertafter!(p, v, IRTools.xcall(println, "loc $v"))
end
return IRTools.finish(p)
end
julia> function h(x)
sin(x)-0.5*cos(x)
end
h (generic function with 1 method)
julia> #code_ir traced(h, 1)
1: (%1, %2)
%3 = Base.getfield(%2, 1)
%4 = Base.getfield(%2, 2)
%5 = Main.sin(%4)
%6 = (println)("loc %3")
%7 = Main.cos(%4)
%8 = (println)("loc %4")
%9 = 0.5 * %7
%10 = (println)("loc %5")
%11 = %5 - %9
%12 = (println)("loc %6")
return %11
julia> traced(h, 1)
loc %3
loc %4
loc %5
loc %6
0.5713198318738266
The rest is left as an exercise. The numbers of the variables are off, because they are, of course, shifted during the transformation. You'd have to add some bookkeeping for that, or use the substitute function on Pipe in some way (but I never quite understood it). If you need the name of the variables, you can get the IR with slots preserved by using a different method of the IR constructor.
(And now the advertisement: I have written something like this. It's currently quite inefficient, but you might get some ideas from it.)

Difference between matlab function 'handle' and python function 'object'

It was suggested in this comment that there is a difference between how Matlab and Python pass around functions. From what I can tell by looking and using the two, there is no difference between the two, but maybe I'm missing something?
In Matlab, you would create a quick function handle like this:
fun = #(x) x.^2 + 1;
In Python, using a lambda function, you could create a similar function like this:
def fun(x):
return x^2
In both languages, it's possible to send the term 'fun' to another function as an argument - but the commenter I linked to insinuated that they are not the same and/or need to be used differently.
What am I missing?
The first comment seems to simply reiterate the idea that you can pass a MATLAB function handle as an argument (although the answer didn't state anything that would make me think otherwise). The second comment seemed to interpret this to mean that the first commenter thought that you couldn't do this in Python and responded to state that you can use either a lambda or pass the function directly.
Regardless, assuming that you use them correctly, a function handle in MATLAB is functionally equivalent to using either a lambda or function object as an input argument in Python.
In python, if you don't append the () to the end of the function, it doesn't execute the function and instead yields the function object which can then be passed to another function.
# Function which accepts a function as an input
def evalute(func, val)
# Execute the function that's passed in
return func(val)
# Standard function definition
def square_and_add(x):
return x**2 + 1
# Create a lambda function which does the same thing.
lambda_square_and_add = lambda x: x**2 + 1
# Now pass the function to another function directly
evaluate(square_and_add, 2)
# Or pass a lambda function to the other function
evaluate(lambda_square_and_add, 2)
In MATLAB, you have to use a function handle because MATLAB attempts to execute a function even if you omit the ().
function res = evaluate(func, val)
res = func(val)
end
function y = square_and_add(x)
y = x^2 + 1;
end
%// Will try to execute square_and_add with no inputs resulting in an error
evaluate(square_and_add)
%// Must use a function handle
evaluate(#square_and_add, 2)

Can an anonymous function in MATLAB have more than one line? [duplicate]

I'd like to do something like this:
>> foo = #() functionCall1() functionCall2()
So that when I said:
>> foo()
It would execute functionCall1() and then execute functionCall2(). (I feel that I need something like the C , operator)
EDIT:
functionCall1 and functionCall2 are not necessarily functions that return values.
Trying to do everything via the command line without saving functions in m-files may be a complicated and messy endeavor, but here's one way I came up with...
First, make your anonymous functions and put their handles in a cell array:
fcn1 = #() ...;
fcn2 = #() ...;
fcn3 = #() ...;
fcnArray = {fcn1 fcn2 fcn3};
...or, if you have functions already defined (like in m-files), place the function handles in a cell array like so:
fcnArray = {#fcn1 #fcn2 #fcn3};
Then you can make a new anonymous function that calls each function in the array using the built-in functions cellfun and feval:
foo = #() cellfun(#feval,fcnArray);
Although funny-looking, it works.
EDIT: If the functions in fcnArray need to be called with input arguments, you would first have to make sure that ALL of the functions in the array require THE SAME number of inputs. In that case, the following example shows how to call the array of functions with one input argument each:
foo = #(x) cellfun(#feval,fcnArray,x);
inArgs = {1 'a' [1 2 3]};
foo(inArgs); %# Passes 1 to fcn1, 'a' to fcn2, and [1 2 3] to fcn3
WORD OF WARNING: The documentation for cellfun states that the order in which the output elements are computed is not specified and should not be relied upon. This means that there are no guarantees that fcn1 gets evaluated before fcn2 or fcn3. If order matters, the above solution shouldn't be used.
The anonymous function syntax in Matlab (like some other languages) only allows a single expression. Furthermore, it has different variable binding semantics (variables which are not in the argument list have their values lexically bound at function creation time, instead of references being bound). This simplicity allows Mathworks to do some optimizations behind the scenes and avoid a lot of messy scoping and object lifetime issues when using them in scripts.
If you are defining this anonymous function within a function (not a script), you can create named inner functions. Inner functions have normal lexical reference binding and allow arbitrary numbers of statements.
function F = createfcn(a,...)
F = #myfunc;
function b = myfunc(...)
a = a+1;
b = a;
end
end
Sometimes you can get away with tricks like gnovice's suggestion.
Be careful about using eval... it's very inefficient (it bypasses the JIT), and Matlab's optimizer can get confused between variables and functions from the outer scope that are used inside the eval expression. It's also hard to debug and/or extent code that uses eval.
Here is a method that will guarantee execution order and, (with modifications mentioned at the end) allows passing different arguments to different functions.
call1 = #(a,b) a();
call12 = #(a,b) call1(b,call1(a,b));
The key is call1 which calls its first argument and ignores its second. call12 calls its first argument and then its second, returning the value from the second. It works because a function cannot be evaluated before its arguments. To create your example, you would write:
foo = #() call12(functionCall1, functionCall2);
Test Code
Here is the test code I used:
>> print1=#()fprintf('1\n');
>> print2=#()fprintf('2\n');
>> call12(print1,print2)
1
2
Calling more functions
To call 3 functions, you could write
call1(print3, call1(print2, call1(print1,print2)));
4 functions:
call1(print4, call1(print3, call1(print2, call1(print1,print2))));
For more functions, continue the nesting pattern.
Passing Arguments
If you need to pass arguments, you can write a version of call1 that takes arguments and then make the obvious modification to call12.
call1arg1 = #(a,arg_a,b) a(arg_a);
call12arg1 = #(a, arg_a, b, arg_b) call1arg1(b, arg_b, call1arg1(a, arg_a, b))
You can also make versions of call1 that take multiple arguments and mix and match them as appropriate.
It is possible, using the curly function which is used to create a comma separated list.
curly = #(x, varargin) x{varargin{:}};
f=#(x)curly({exp(x),log(x)})
[a,b]=f(2)
If functionCall1() and functionCall2() return something and those somethings can be concatenated, then you can do this:
>> foo = #() [functionCall1(), functionCall2()]
or
>> foo = #() [functionCall1(); functionCall2()]
A side effect of this is that foo() will return the concatenation of whatever functionCall1() and functionCall2() return.
I don't know if the execution order of functionCall1() and functionCall2() is guaranteed.

OOP Matlab inheritance issue with Matlab coder (Simulink MATLAB Function block)

I have defined an abstract base class measurementHandler < handle which defines the interface for all inherited classes. Two subclasses of this class are a < measurementHandler and b < measurementHandler.
I now have a function which should return a handle to an instance of either of these subclasses (depending on the function arguments) to it's caller. Consider something like this:
function returnValue = foobar(index)
if index == 0
returnValue = a();
else
returnValue = b();
end
end
This function is enclosed in a MATLAB Function block in Simulink (2013a). When I try to simulate the system, I get the following error:
Type name mismatch (a ~= b).
Can anybody suggest a workaround for this which still allows me to take advantage of OOP & inheritance when using Simulink?
This kind of pattern is possible in MATLAB Function block only if the "if" condition can be evaluated at compile time. The types cannot be switched at run-time. Can you make the index value a constant at the call site?
The main reason to use this pattern was to iterate over a measurementHandler Array, while these all can have custom implementations. I was able to do this by unrolling the loop with the coder.unroll directive. Example for the enclosing MTALAB Function block:
function result = handleAllTheMeasurements(someInputs)
%#codegen
for index = coder.unroll(1:2)
measurementHandler = foobar(index);
measurementHandler.handleMeasurement(someInputs);
end
result = something;
end
This way, the for loop gets unrolled at compile time and the return type of the function is well defined for each separate call.