# Peeling functions calling functions

**URL:** <https://discourse.julialang.org/t/peeling-functions-calling-functions/60452>\
**Category:** General Usage\
**Created:** [May 3, 2021, 8:46am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452 "2021-05-03T08:46:41Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [May 3, 2021, 8:46am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/1 "2021-05-03T08:46:41Z")

</div>

I wonder, if there is a way in Julia to “peel away” an outer function calling an inner function

```julia
julia> f(x)=sqrt(abs2(x))

```

The task would be to generate a function `g(x)=abs2(x)` by only having access to `f` and knowing that the outer part is in fact `sqrt()`. I would like to “peel” this function, since this could help me with overwriting the broadcast mechanism for an array type to avoid calculating first the square-root of something known to be positive (radius of center), just to then square it again.  
Can this be done in Julia? Any help would be appreciated.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [May 3, 2021, 8:53am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/2 "2021-05-03T08:53:51Z")

</div>

I would define `g(x) = abs2(x)` and redefine `f(x) = sqrt(g(x))`.

---

<div class="post-metadata">

**Author:** ![gustaphe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gustaphe/32/18174_2.png) [@gustaphe](https://discourse.julialang.org/u/gustaphe)\
**Post date:** [May 3, 2021, 8:54am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/3 "2021-05-03T08:54:06Z")

</div>

I’m going to go ahead and say “no”. There might technically be some shenanigans you can do, but it’s going to produce illegible code. If the cost of squaring the number is too high, you better get access to the inner function.

---

<div class="post-metadata">

**Author:** ![cvanaret](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cvanaret/32/11594_2.png) [@cvanaret](https://discourse.julialang.org/u/cvanaret)\
**Post date:** [May 3, 2021, 9:43am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/4 "2021-05-03T09:43:49Z")

</div>

You could generate the symbolic expression of the function and manipulate that yourself:

```julia
julia> using ModelingToolkit

julia> @variables x
(x,)

julia> f(x) = sqrt(abs2(x))
f (generic function with 1 method)

julia> expression = f(x)
sqrt(abs2(x))

julia> dump(expression)
Operation
  op: sqrt (function of type typeof(sqrt))
  args: Array{Expression}((1,)) Expression[abs2(x)]

```

---

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [May 3, 2021, 10:49am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/5 "2021-05-03T10:49:18Z")

</div>

Interesting approach using symbolic variables. The problem is that this violates the initial idea that only access to an already existing `f` is provided. I was hoping that Julia internally also stores something along the same way as your ‘dump’ function can show.

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [May 3, 2021, 11:05am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/6 "2021-05-03T11:05:25Z")

</div>

If you only have access to the _function_ `f` and not the _expression_ of `f`, then there is nothing you can do using high-level code. People may probably be able to access the internals with low-level representations (e.g. lowered) but that would be a big waste of energy for a problem that could potentially be solved differently. Maybe you could share your motivations behind trying to access the inner function?

Notice that if you had access to the _expression_ of `f` you could manipulate it without any package:

```julia
julia> f = :(sqrt(abs2(x)))
:(sqrt(abs2(x)))

julia> dump(f)
Expr
  head: Symbol call
  args: Array{Any}((2,))
    1: Symbol sqrt
    2: Expr
      head: Symbol call
      args: Array{Any}((2,))
        1: Symbol abs2
        2: Symbol x

```

---

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [May 3, 2021, 11:31am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/7 "2021-05-03T11:31:46Z")

</div>

Ok, here some more on the motivation: @roflmaostc and I wrote a package called `IndexFunArrays.jl` which allows you to very conveniently work with expressions on indices that look like arrays but are behave lazy. One such convenient function is `rr(sizeTuple)`. It really is a shorthand for `sqrt.(rr2())`. All such functions have a bunch of possible convenient ways of using them which comes down to various ways of defining the `offset` and `scale` parameters. However, these user parameters are currently NOT stored in the array structure but are molded into the `generate` function which is stored by the array.  
As many users naively may write things like `rr((100,100)) .< 20.4` and are probably not aware that `rr2((100,100)) .< abs2(20.4)` would be a lot faster, I thought about overwriting the corresponding `broadcast` function such that it removes the completely unnecessary `sqrt()`. There are similar arguments to be made for users writing `abs2.(rr((100,100)))` which should be replaced by `rr2((100,100))`. Anyway, a solution would be to store offset and scale as this information would be enough to synthesize the necessary position conversion which is stored in the `generator`. But then I would prefer not to bloat the array type with such unnecessary information.

---

<div class="post-metadata">

**Author:** ![gustaphe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gustaphe/32/18174_2.png) [@gustaphe](https://discourse.julialang.org/u/gustaphe)\
**Post date:** [May 3, 2021, 1:03pm UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/8 "2021-05-03T13:03:29Z")

</div>

I don’t know what `rr2` does, but if you are just removing `sqrt` from `rr` if `x>=0`, why not just define `rr` to do the check:

```julia
rr(x) = x<0 ? sqrt(rr2(x)) : rr2(x)

```

?

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [May 3, 2021, 1:11pm UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/9 "2021-05-03T13:11:01Z")

</div>

Using symbolic variables is the only way to do this at a high level. It doesn’t violate the original idea as long as the functions are written in Julia.

You pass symbolic variables in and you get a symbolic form of the function back, provided various technical requirements are met. This is often called “tracing” through the function.

---

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [May 3, 2021, 1:27pm UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/10 "2021-05-03T13:27:23Z")

</div>

`rr()` generates the ND distance to the center (as specified by an optional `offset`). `rr2()` generates the square of the distance to the center, i.e. it does not require a square-root. Sorry, your suggestion misses the point of trying to fuse functions in dependence of the usage. However, one can hope that at least one of the cases `sqrt(abs2())` may be picked up lowlevel and converted to `abs`. Yet I doubt that the compiler can pick up the other case with the comparison.

---

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [May 3, 2021, 1:30pm UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/11 "2021-05-03T13:30:04Z")

</div>

I am not sure if this can really help here. The array must look like an array in all aspects, yet internally it stores a function. In the inner loop the getindex resolves the calculation. I suspect “resolving” the symbolic variable there may be a bad idea. Of course, the symbolic expression could be stored in addition, but then I can also store offset and scale…

---

<div class="post-metadata">

**Author:** ![gustaphe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gustaphe/32/18174_2.png) [@gustaphe](https://discourse.julialang.org/u/gustaphe)\
**Post date:** [May 3, 2021, 1:42pm UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/12 "2021-05-03T13:42:25Z")

</div>

> fuse functions in dependence of the usage

I don’t understand this. So you are using `rr` and `rr2` from some other package? And why is this `sqrt(abs2(x))` cancellation something a user would expect your array type to do, rather than an optimization in the package that defines `rr` (or something they would do manually)?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [May 4, 2021, 8:12am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/13 "2021-05-04T08:12:41Z")

</div>

> [@RainerHeintzmann](#):
>
> if there is a way in Julia to “peel away” an outer function calling an inner function

Generally there isn’t, but you can design an API to expose this functionality:

```julia
struct F{G}
    g::G
end

(f::F)(x) = sqrt(f.g(x))

peel(f::F) = f.g

myf = F(abs2)
myf(4.0)
peel(myf)

```

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 4, 2021, 9:48am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/14 "2021-05-04T09:48:07Z")

</div>

> [@RainerHeintzmann](#):
>
> I would like to “peel” this function, since this could help me with overwriting the broadcast mechanism for an array type to avoid calculating first the square-root of something known to be positive (radius of center), just to then square it again.

If you know `x` to be positive, it might be worthwhile to make that information available (e.g. via a type parameter) to dispatch and write a `abs2` and `sqrt` function that just pass those types through. Could also be done via a small wrapper.

E.g.

```julia
struct KnownPositive{T}
  x::T
end

abs2(m::MyMatrix) = ispositive(m) ? abs2(KnownPositive(m)) : real_abs2(m)
abs2(k::KnownPositive) = k
sqrt(k::KnownPositive) = k.x

```

You need ownership/control over the type of your matrix though, which I assume you have since you mention customizing broadcasting. You’ll also have to customize other parts of your code, depending on where the result of `abs2` ends up.

---

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [May 4, 2021, 10:42am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/15 "2021-05-04T10:42:57Z")

</div>

Yes. This boils down to storing the unpeeled function explicitly. It would work but is not the solution of choice for me. Storing the offsets and scales is then a more generic option, I guess.

---

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [May 4, 2021, 10:45am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/16 "2021-05-04T10:45:31Z")

</div>

Not really. abs2 hast to take the square and the `sqrt` has to annihilate with the `abs2`. but using a positive type is the right choice, if one wanted to be generic here. However, maybe also at the lowering level Julia could do something about such a mechanism to speed up its performance? Maybe it already does so?

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 4, 2021, 11:02am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/17 "2021-05-04T11:02:05Z")

</div>

> [@RainerHeintzmann](#):
>
> However, maybe also at the lowering level Julia could do something about such a mechanism to speed up its performance?

There’s nothing special about `sqrt` and `abs2` - they are just regular functions. Eliminating those specific constructs would mean special casing them, which (apart from the fact that it depends on the types in question whether it’s allowed in the first place) would require making lowering more complicated for questionable general gain.

Generalising this behaviour to eliminate “redundant” function application would require incorporating something like Symbolics.jl into the julia compiler, which would increase compile times dramatically (and you’d also have to have all those transforms defined for different types where it’s valid and make sure you don’t make a mistake - e.g. `sqrt(abs2(1//21)) == 1//21` is false).

You basically need the wrapper type to decide this via dispatch at all, since for various edge cases in terms of value, the transform is not always valid:

```julia
julia> prevfloat(Inf)                
1.7976931348623157e308               
                                     
julia> prevfloat(Inf) |> abs2 |> sqrt
Inf                                  

julia> 0.25 |> abs2 |> sqrt
0.25                       

```

---

<div class="post-metadata">

**Author:** ![RainerHeintzmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rainerheintzmann/32/19726_2.png) [@RainerHeintzmann](https://discourse.julialang.org/u/RainerHeintzmann)\
**Post date:** [May 4, 2021, 11:20am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/18 "2021-05-04T11:20:34Z")

</div>

Good point. I guess this has to do with the user choice `IEEE` float performance or fast optimization.  
I have to admit that I know next to nothing about julia’s or LLVM internal optimizations.  
If I write `1 .*A .+ 5 .+ 2 .*A .+7` with array type `A` does it internally get transformed to `12 .+ 3 .*A`?  
If not, maybe packages like `Tullio.jl` can do this?  
If yes, then such optimizations should have similar issues. I think the user would in almost all cases want the performant version and the case `julia> prevfloat(Inf) |> abs2 |> sqrt` is rather a problem than a solution.  
I heard rumors that a for-loop adding a number is sometimes entirely replaced by a simple multiplication by LLVM. If this is the case, than this also violates your implicit suggestion to obtain unmodified results at all costs.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 4, 2021, 11:34am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/19 "2021-05-04T11:34:50Z")

</div>

> [@RainerHeintzmann](#):
>
> If I write `1 .*A .+ 5 .+ 2 .*A .+7` with array type `A` does it internally get transformed to `12 .+ 3 .*A` ?

No, though depending on the type of `A`, `A` may be replaced by a constant if the creator of that type allows for that specialization (for example if `A` is not a materialized matrix at all but [an iterator behaving like a matrix](https://www.youtube.com/watch?v=jS9eouMJf_Y)).

That transform again requires something like `Symbolics.jl` and very specific semantics to be allowed to do (remember, `*` is also just a regular function and may have side effects for some custom types).

> [@RainerHeintzmann](#):
>
> If not, maybe packages like `Tullio.jl` can do this?

Yes, a macro could be written to do this, since what you’re asking for is a syntactic transform (though that again is limited to code the macro sees - `@remove_redundancy sqrt(abs2(x))` could just spit out `x`, whereas `@remove_redundancy f(x)` with `f(x) = sqrt(abs2(x))` can not, since the macro can’t see “into” `f`).

> [@RainerHeintzmann](#):
>
> If yes, then such optimizations should have similar issues.

Indeed they have, though that’s not what Tullio.jl is doing specifically. Those transforms are basically what `--fastmath` is doing in some places.

> [@RainerHeintzmann](#):
>
> I heard rumors that a for-loop adding a number is sometimes entirely replaced by a simple multiplication by LLVM. If this is the case, than this also violates your implicit suggestion to obtain unmodified results at all costs.

Those transforms are few and far between and only applied if all involved behaviour can’t be distinguished (in terms of returned values). You’re probably thinking of the compiler replacing a naive sum over `1:n` with the summation formula `(n*(n+1))/2` or even the resulting constant, if `n` is known as well. Since they’re only applied if you can’t distinguish them, the results (in that sense) are “unmodified”. If I recall correctly, that specific transform is only applied for integer arguments, since floating point summation is not associative and you will get a different result.

This is not exclusive to LLVM, by the way - GCC does the same kinds of transforms, as do most sufficiently advanced compilers.

---

<div class="post-metadata">

**Author:** ![gustaphe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gustaphe/32/18174_2.png) [@gustaphe](https://discourse.julialang.org/u/gustaphe)\
**Post date:** [May 4, 2021, 11:39am UTC](https://discourse.julialang.org/t/peeling-functions-calling-functions/60452/20 "2021-05-04T11:39:08Z")

</div>

> If I write 1 .\*A .+ 5 .+ 2 .\*A .+7 with array type A does it internally get transformed to 12 .+ 3 .\*A?

![image](https://global.discourse-cdn.com/julialang/original/3X/a/e/ae0df6ddc946b88581ae72e7e5ceff59288162b1.png)

No.
