# Functional inverse

**URL:** https://discourse.julialang.org/t/functional-inverse/10959
**Category:** Internals & Design
**Created:** [May 17, 2018, 4:31pm UTC](https://discourse.julialang.org/t/functional-inverse/10959 "2018-05-17T16:31:05Z")
**Posts on this page:** 17
**Page:** 1

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [May 17, 2018, 4:31pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/1 "2018-05-17T16:31:05Z")

</div>

An idea: A function `finv` that returns the functional inverse of a function. For instance

```julia
finv(::typeof(cos)) = acos

```

I thought of this not for `cos`, but for a particular function whose inverse does not have a recognized name nor a conventional computer function name like arccosine → `acos`.

Two possible uses:

1. discoverability in the case that `myfunc` is well known, but there is no standard name for the inverse. Instead of remembering `myfunc_inv(x)` or `invmyfunc(x)` or whatever, it is always `finv(myfunc)(x).
2. To get the functional inverse of an unknown function. Maybe in a computation similar to automatic differentiation.

Possible complications are how to handle multiple branches and multiple arguments.

Are there outstanding cases where this would be useful, or is my use case more or less isolated ? A related question, is there already a convention used in some packages that I have not discovered?

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [May 17, 2018, 4:41pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/2 "2018-05-17T16:41:05Z")

</div>

Sure, this is definitely something you could implement for specific functions, although I would guess that the majority of functions used in practical code don’t have well-defined inverses. But I think your idea of implementing `finv(::typeof(f))` for various functions `f` is sound.

On the other hand, the existence of a computation that could invert an arbitrary function efficiently would, at the very least, prove [P = NP](https://en.wikipedia.org/wiki/P_versus_NP_problem) and probably render all of computer science obsolete. So that part’s probably not going to happen 😉

---

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [May 17, 2018, 5:24pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/3 "2018-05-17T17:24:21Z")

</div>

> To get the functional inverse of an unknown function. Maybe in a computation similar to automatic differentiation.

A package that implements the analysis-stack of inverse function theorem / implicit function theorem via AD + Newton + symbolic shortcuts when feasible would be really cool, but I know of no precedent of any library/language doing this well. Unfortunately this sounds like a really big project (if some terms in your function are themselves implicit functions, then you need to collapse the stack and use shortcuts).

---

<div class="post-metadata">

### Author: ![ExpandingMan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/expandingman/32/866_2.png) [@ExpandingMan](https://discourse.julialang.org/u/ExpandingMan)
#### Post date: [May 17, 2018, 5:38pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/4 "2018-05-17T17:38:16Z")

</div>

While we are obviously not going to have an algorithm that does functional inverse of cryptographic hash functions, I agree that it would be useful to just have a function where the inverses are explicitly defined on everything you can write an inverse for. I even seem to remember having written an API for a package that required people to define `inv(::typeof(f))` for functions they want to use.

By the way, you should be able to just use `inv`, I don’t see any reason why it would need a special name as it doesn’t have methods for specific functions like that.

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [May 17, 2018, 5:43pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/5 "2018-05-17T17:43:52Z")

</div>

Well my main motivation was discoverability and maybe reducing verb count, rather than dealing comprehensively with functional routines. For instance

```julia
finv(::typeof(lambertw))= z -> z*exp(z)

```

And I have at least one other use case.

But, if you really think there are algorithms that would like to use routines that produce numerical functional inverses, you could do something like this.

```julia
function nofunc end
finv(f::Function) = nofunc

```

Then your algorithm that wants inverses could include a catchall method for `nofunc`, and optimized methods for those functions that have defined a method for `finv`.

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [May 17, 2018, 5:45pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/6 "2018-05-17T17:45:37Z")

</div>

There’s also this cute trick:

```julia
julia> Base.literal_pow(::typeof(^), ::typeof(sin), ::Val{-1}) = asin # edited silly typo

julia> (sin^-1)(1)
1.5707963267948966

```

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [May 17, 2018, 5:46pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/7 "2018-05-17T17:46:38Z")

</div>

This is exactly what i guessed. It has been done before, and may as well be made general. But, `inv` is used for multiplicative inverse (and its generalization to matrices) which is a different concept. And `inv` is in base. In any case, the most important thing is to have a 500 post discussion about whether it belongs in base and which concept gets primacy for using `inv`😉

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [May 17, 2018, 5:56pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/8 "2018-05-17T17:56:48Z")

</div>

That is too temptingly cute. (but you meant `asin`)… Or on second thought, it is more obvious what `(sin^-1)(x)` means than what `finv(sin)(x)` means.

---

<div class="post-metadata">

### Author: ![ExpandingMan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/expandingman/32/866_2.png) [@ExpandingMan](https://discourse.julialang.org/u/ExpandingMan)
#### Post date: [May 17, 2018, 6:01pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/9 "2018-05-17T18:01:18Z")

</div>

I don’t think the `literal_pow` thing is such a good idea, because then it really does look like a multiplicative inverse. Same reason I use \arccos(x) instead of \cos^{-1}(x).

---

<div class="post-metadata">

### Author: ![jlperla](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlperla/32/34332_2.png) [@jlperla](https://discourse.julialang.org/u/jlperla)
#### Post date: [May 17, 2018, 6:07pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/10 "2018-05-17T18:07:10Z")

</div>

It may not be exactly what you are looking for, but I think the most general way to do this is with interval arithmetic, i.e. [https://github.com/JuliaIntervals/IntervalContractors.jl](https://github.com/JuliaIntervals/IntervalContractors.jl) Which is a combination of analytics and provable numerical methods on intervals.

Guess it depends on the application, though… But if you don’t know about `JuliaIntervals`, it is a fun read nevertheless!

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [May 17, 2018, 6:07pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/11 "2018-05-17T18:07:21Z")

</div>

I agree with you for written math. You’ve seen early 20th century papers with `sin x`, etc. And the same thought went through my head just now. But in the code you need parens, which disambiguate: `(sin^-1)(x)`.

---

<div class="post-metadata">

### Author: ![ExpandingMan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/expandingman/32/866_2.png) [@ExpandingMan](https://discourse.julialang.org/u/ExpandingMan)
#### Post date: [May 17, 2018, 6:10pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/12 "2018-05-17T18:10:19Z")

</div>

I still think it’s more common not to use parentheses for functions with `\textrm` text. I personally like them to have parentheses.

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [May 17, 2018, 6:13pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/13 "2018-05-17T18:13:44Z")

</div>

That looks cool. David’s interval project is great. But, I have to say, I don’t like `cos!`, because `!` does not mean mutating function in this case. … we are drifting. That’s ok. Hendrix’s [drifting](https://www.google.es/search?q=hendrix+drifting&oq=hendrix+drifting+&aqs=chrome..69i57j0l5.7729j0j8&sourceid=chrome&ie=UTF-8) was looping for an hour or so this morning.

---

<div class="post-metadata">

### Author: ![chakravala](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chakravala/32/6832_2.png) [@chakravala](https://discourse.julialang.org/u/chakravala)
#### Post date: [May 18, 2018, 5:05am UTC](https://discourse.julialang.org/t/functional-inverse/10959/14 "2018-05-18T05:05:31Z")

</div>

> [@jlapeyre](#):
>
> A function `finv` that returns the functional inverse of a function.

You can define such a type of function with [Reduce.jl](https://github.com/chakravala/Reduce.jl) symbolic package:

```Julia
julia> using Reduce

julia> finv(f::Function) = collect(Algebra.solve(:($f(x) == y),:x))
finv (generic function with 1 method)

julia> finv(cos)
2-element Array{Expr,1}:
 :(x = acos(y) + 2 * arbint(5) * π)     
 :(x = -((acos(y) - 2 * arbint(5) * π)))

```

Also, to select the principal branch, set `allbranch` to off

```Julia
julia> allbranch(false)
false

julia> finv(cos)
1-element Array{Expr,1}:
 :(x = acos(y))

```

---

<div class="post-metadata">

### Author: ![chakravala](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chakravala/32/6832_2.png) [@chakravala](https://discourse.julialang.org/u/chakravala)
#### Post date: [May 18, 2018, 5:30am UTC](https://discourse.julialang.org/t/functional-inverse/10959/15 "2018-05-18T05:30:47Z")

</div>

Alternatively, if you want to also evaluate the function at `x`, you can do it like this

```nohighlight
julia> using Reduce

julia> allbranch(false)
false

julia> @generated function finv(x,::Val{f}) where f
           out = Algebra.solve(:($f(y) == x),:y)
           :(@fastmath $(out[1].args[2]))
       end
finv (generic function with 1 method)

julia> finv(x,f::Function) = finv(x,Val(f))
finv (generic function with 2 methods)

julia> finv(1,sin)
1.5707963267948966

```

This allows you to evaluate the inverse at any `x` of any function `f` that is invertible.

---

<div class="post-metadata">

### Author: ![mschauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mschauer/32/13946_2.png) [@mschauer](https://discourse.julialang.org/u/mschauer)
#### Post date: [May 18, 2018, 7:11am UTC](https://discourse.julialang.org/t/functional-inverse/10959/16 "2018-05-18T07:11:20Z")

</div>

Such inverses bound to function names have nice applications in pattern matching and destructuring assignmens,

```julia
@match Polar(r, phi) = z

```

Old issue:

[https://github.com/kmsquire/Match.jl/issues/15](https://github.com/kmsquire/Match.jl/issues/15)

---

<div class="post-metadata">

### Author: ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)
#### Post date: [May 18, 2018, 2:47pm UTC](https://discourse.julialang.org/t/functional-inverse/10959/17 "2018-05-18T14:47:08Z")

</div>

Those are some interesting ideas. But, adding a dependency, especially a binary dependency, is not a good option for something so simple.

For the moment, I have decided on `finv` and pushed changes to github. For [`LambertW.jl`](https://github.com/jlapeyre/LambertW.jl/blob/master/src/LambertW.jl#L20), I have

```julia
finv(::typeof(lambertw)) = z -> z * exp(z)

```

For [EmpiricalCDFs.jl](https://github.com/jlapeyre/EmpiricalCDFs.jl/blob/master/src/cdfs.jl#L209), the empirical CDF is a callable object. I use essentially the following

```julia
function finv(cdf::EmpiricalCDF)
    function (c::Real)
        _inverse(cdf,c)
    end
end

```

These seem consistent and generalize well.
