# Introspecting into a function?

#1

Hi, I’m not sure if I’m using the right terminology here but essentially what I want to do is to make a function (or macro) which takes another function as it’s argument and looks inside that argument function to see what it does.

So here’s an example case. I’ve defined a method `*(f1::Function, f2::Function) = t -> f1(t) * f2(t)`

And then I want my function `D(f::Function)` to look inside `f` without evaluating it and see if `f` is the multiplication of two functions. Ie. if `f = sin * cos` Then `D(f)` should return `D(sin) * cos + sin * D(cos)`

Does anyone have any ideas on how to go about doing this? I’ve has a hard time with the documentation on this.

To give some background on why I’m interested in this, I recently watched this talk: Physics in Clojure where the author talks about his experience porting scmutils from the book Structure and Interpretation of Classical Mechanics (something of a sequel to Structure and Interpretation of Computer Programs) from Scheme to Clojure.

This got me really interested in attempting this with Julia though its a bit of an uphill battle as I’m not proficient enough with Scheme and Clojure to understand the author’s source code for scmutils and the documetation is very sparse. However, I can infer how the programs are supposed to behave and so its turned into a fun little side project to attempt to reimplement scmutils in Julia.

#2

Waiting for https://github.com/jrevels/Cassette.jl might be your best bet.

You could also try out https://github.com/SimonDanisch/Sugar.jl.

#3

Won’t cassette require evaluation of the function, which OP doesn’t want?

@Mason Have you considered macros? If `*(f1::Function, f2::Function) = @store_definition t -> f1(t) * f2(t)`, you can turn the anonymous function into a callable object (containing the anonymous function, and the definition). Then it’s straight-forward to check if it’s a multiplication.

Or you could straight up have `*(f1::Function, f2::Function) = Multiply(f1, f2)`, where Multiply is a callable object.

#4

Do you need your arguments to be “black box” functions? If not, there are a couple of approaches I can think of:

• Create a “functiony” datatype (and maybe come up with a better term for it ), representing multiplication of functions, and maybe other cominators if you need. Then you can define a multiplication of these things to just look at the existing structure and extend accordingly.
• Create functions as expressions, and evaluate them later. Multiplication can then look at the code directly. I’m doing something like this for Soss.

#5

Can you back up and summarize what underlying problem you are trying to solve? Why do you need to write functions that analyze other functions without executing them?

#6

My apologies, I’ll edit my original post.

Great, Cassette looks exciting but for now at least, Sugar might do the trick.

Evaluation isn’t actually a huge deal, I just don’t want to have to call `D` as `D((sin*cos)(t))`, I want it to act on just the function `sin*cos`.

#7

A natural way to do this in Julia, without introspection, is e.g. `D(f) = x -> ForwardDiff.derivative(f, x)` using the `ForwardDiff` package for automatic differentiation. Then you can do `D(sin ∘ cos)` etcetera. (Note that Julia 0.6 has a generic function-composition operator `∘`, typed by tab-completing `\circ` in the REPL etc.)

#8

I deal with numeric and symbolic inputs though so using multiple dispatch I already have that `(D(f::Function))(t::Number)` is the automatic derivative of `f` but I need `(D(f::Function))(t::Union{Expr, Symbol})` to perform symbolic differentiation using the calculus rules I’ve written.

From what I’ve seen here though, doing the introspection does not apparently worth it but I think I have another idea that I’ll try out and if it works I’ll report back.

#9

Okay, so I got around my problem and I did it without needing to introspect into functions. In case anyone’s interested in how I did this, I made a derivative function `D` using forward mode automatic differentiation but using symbolic arguments instead of numeric which turned out to be really easy to implement and much better than the method I was using before which involved trying to do pattern matching and term rewriting to apply differentiation rules.

#10

That sounds nice - which symbolic package did you use? Would you be interested in sharing the code?

#11

I’m actually not using a symbolic package, I wanted total control over evaluation and simplification so I rolled my own. Its still in the early stages but I’ll share some snippets here to show you whats going on but I think I’ll put the whole thing up on a github repo soon.

The idea is that I’ve added methods to all the basic mathematical functions such that

``````julia> :x + :y
:(x + y)
julia> :x - 5
:(x + -5)   #I'm not sure I'm super happy with this choice but it makes simplification much easier.
julia> sin(:x)
:(sin(x))
``````

etc.

And then I made a simplification algorithm which looks for common mathematical patterns in the expression tree and applies replacement rules to them and then keeps on looping until the expression stops changing ie.

``````julia> :(x^1) |> expansion_loop
x
julia> :(0 * x) |> expansion_loop
0
julia> :(1 * x) |> expansion_loop
x
julia> :(0 + x) |> expansion_loop
x
``````

etc.

Finally, to take derivatives of symbolic functions I made a struct

``````Mathy = Union{Number, Symbol, Expr}

struct Dual_Number
real::Mathy
infinitesimal::Mathy
end

function dual_number(a::Mathy, b::Mathy)
if b == 0
a
else
Dual_Number(a, b)
end
end

dual_number(a) = dual_number(0, a)
``````

and then screwed around with how dual numbers are displayed, ie.

``````function Base.show(io::IO, dual::Dual_Number)
if (dual.infinitesimal isa Number) && (dual.infinitesimal < 0)
op = "-"
else
op = "+"
end
real_string = dual.real == 0 ? "" : "\$(dual.real) \$op "
infinitesimal_string = dual.infinitesimal == 0 ? "" :
abs(dual.infinitesimal) == 1 ? "ϵ" :
(dual.infinitesimal isa Expr) && (dual.infinitesimal.args[1] == :+ || dual.infinitesimal.args[1] == :-) ? "(\$(dual.infinitesimal))ϵ" :
"\$(dual.infinitesimal)ϵ"
print(io, "\$real_string\$infinitesimal_string")
end
``````

Next, I’ve made methods for some standard mathematical functions for working with dual numbers that are agnostic about numbers versus symbols and expressions (because I can compose all of them). The idea here is that if I define

``````
conj(a::Dual_Number) = dual_number(a.real, -(a.infinitesimal))

+(a::Dual_Number, b::Dual_Number) = dual_number(a.real + b.real, a.infinitesimal + b.infinitesimal)
+(a::Dual_Number, b::Mathy) = dual_number(a.real + b, a.infinitesimal)
+(a::Mathy, b::Dual_Number) = dual_number(a + b.real, b.infinitesimal)

-(a::Dual_Number, b::Dual_Number) = dual_number(a.real - b.real, a.infinitesimal - b.infinitesimal)
-(a::Dual_Number, b::Mathy) = dual_number(a.real - b, a.infinitesimal)
-(a::Mathy, b::Dual_Number) = dual_number(a - b.real, b.infinitesimal)

*(a::Dual_Number, b::Dual_Number) = dual_number(a.real * b.real, a.infinitesimal * b.real + a.real * b.infinitesimal)
*(a::Dual_Number, b::Mathy) = dual_number(a.real * b, a.infinitesimal * b)
*(a::Mathy, b::Dual_Number) = dual_number(a * b.real, a * b.infinitesimal)

/(a::Dual_Number, b::Dual_Number) = b.real != 0 ? (a * conj(b))/(b.real)^2 : Inf
/(a::Dual_Number, b::Mathy) = dual_number(a.real / b, a.infinitesimal / b)
/(a::Mathy, b::Dual_Number) = b.real != 0 ? (a * conj(b))/(b.real)^2 : Inf

^(a::Dual_Number, b::Mathy) = dual_number(a.real^b, b * a.real^(b-1) * a.infinitesimal)
^(a::Dual_Number, b::Integer) = dual_number(a.real^b, b * a.real^(b-1) * a.infinitesimal)
^(a::Mathy, b::Dual_Number) = dual_number(b^a.real, log(b) * a^b.real * a.infinitesimal)

log(a::Dual_Number) = dual_number(log(a.real), 1/a.real * a.infinitesimal)

sin(a::Dual_Number) = dual_number(sin(a.real), cos(a.real)*a.infinitesimal)
cos(a::Dual_Number) = dual_number(cos(a.real), -sin(a.real)*a.infinitesimal)
``````

The idea here is that if I define `ϵ = dual_number(0, 1)` then `ϵ^2 == 0` so `ϵ` is like a very small (infinitesimal) number and for any function `f(x)`, `f(x + ϵ) = f(x) + ϵ f'(x)`

I then made a derivative function which takes a function `f` and returns a function which when evaluated will evaluate `f(t + ϵ)` and extracts out the infinitesimal part which will be the automatic derivative of `f` and then simplifies that result.

``````ϵ = dual_number(0, 1)
function D(f::Function)
t::Mathy ->  f(t + ϵ).infinitesimal |> expansion_loop
end
``````

With this I can do stuff like

``````julia> f(x) = log(sin((x^2)));
julia> D(f)(:x)
:((1 / sin(x ^ 2)) * (cos(x ^ 2) * (2x)))

``````

which is correct(!!!) but could be simplified a bit more.

Sorry that turned into a lot of code but I was excited enough that I wanted to share what I had done. Once this is a bit more polished I’ll maybe make some blog posts about it if people are interested.