Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add setinverse #25

Merged
merged 6 commits into from
Sep 28, 2022
Merged

Add setinverse #25

merged 6 commits into from
Sep 28, 2022

Conversation

oschulz
Copy link
Collaborator

@oschulz oschulz commented Sep 23, 2022

Closes #18

CC @cscherrer

@oschulz
Copy link
Collaborator Author

oschulz commented Sep 23, 2022

@devmotion, I couldn't come up with a better function name than setinverse - but maybe it's Ok since we also have things like a non-mutating setfield in other packages?

@codecov
Copy link

codecov bot commented Sep 23, 2022

Codecov Report

Base: 100.00% // Head: 100.00% // No change to project coverage 👍

Coverage data is based on head (62bca9b) compared to base (34c1adf).
Patch coverage: 100.00% of modified lines in pull request are covered.

Additional details and impacted files
@@            Coverage Diff            @@
##            master       #25   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            3         4    +1     
  Lines           74        80    +6     
=========================================
+ Hits            74        80    +6     
Impacted Files Coverage Δ
src/setinverse.jl 100.00% <100.00%> (ø)

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

Copy link
Contributor

@cscherrer cscherrer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! I had two very minor nit-picks :)

src/setinverse.jl Outdated Show resolved Hide resolved
src/setinverse.jl Outdated Show resolved Hide resolved
oschulz and others added 2 commits September 23, 2022 16:42
Co-authored-by: Chad Scherrer <[email protected]>
Co-authored-by: Chad Scherrer <[email protected]>
@oschulz
Copy link
Collaborator Author

oschulz commented Sep 23, 2022

Thanks for the corrections, @cscherrer !

@oschulz
Copy link
Collaborator Author

oschulz commented Sep 23, 2022

Ok, docgen is fixed too now.


```@docs
InverseFunctions.square
InverseFunctions.FunctionWithInverse
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it's not exported and not intended to be constructed directly, I wonder if it should be omitted from the docs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought people might want to have the option to dispatch on it, in low-level uses cases and so on, that's why I made it party of the official API.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assumed that this was the motivation. I wonder, however, how often one would actually want to dispatch on FunctionWithInverse. I assume for many cases it would be simpler to just use unwrap_f (or something equivalent of the same name) and inverse - similar to the setinverse case in this PR.

Copy link
Collaborator Author

@oschulz oschulz Sep 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder, however, how often one would actually want to dispatch on FunctionWithInverse.

We may actually have occasion to do that in the pushforward measure in MeasureBase (in the context of JuliaMath/MeasureBase.jl#89, since PushforwardMeasure stores both forward and inverse function for performance reasons). Not sure yet - but it's an interesting option (we may want to extract forward and inverse from FunctionWithInverse). So there's at least one possible use case, so there may be more. And it doesn't cost us anything, I wouldn't expect FunctionWithInverse to change in breaking ways in the future.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since PushforwardMeasure stores both forward and inverse function for performance reasons

To obtain these you don't have to specialize on FunctionWithInverse though. You could just store _unwrap_f(f) and inverse(f) if an arbitrary f is provided.

src/setinverse.jl Outdated Show resolved Hide resolved
src/setinverse.jl Outdated Show resolved Hide resolved
src/setinverse.jl Outdated Show resolved Hide resolved
src/setinverse.jl Outdated Show resolved Hide resolved
src/setinverse.jl Outdated Show resolved Hide resolved
src/setinverse.jl Outdated Show resolved Hide resolved
src/setinverse.jl Outdated Show resolved Hide resolved
src/setinverse.jl Outdated Show resolved Hide resolved

```@docs
InverseFunctions.square
InverseFunctions.FunctionWithInverse
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assumed that this was the motivation. I wonder, however, how often one would actually want to dispatch on FunctionWithInverse. I assume for many cases it would be simpler to just use unwrap_f (or something equivalent of the same name) and inverse - similar to the setinverse case in this PR.

@aplavin
Copy link
Contributor

aplavin commented Sep 25, 2022

I couldn't come up with a better function name than setinverse - but maybe it's Ok since we also have things like a non-mutating setfield in other packages?

Maybe, withinverse discussed in the linked issue would be more intuitive?
set... functions in packages like Accessors and ConstructionBase tend to mean "set an already existing part to a new value", not "add/insert a new part to the object".

Just a suggestion.

@oschulz
Copy link
Collaborator Author

oschulz commented Sep 26, 2022

Maybe, withinverse discussed in the linked issue would be more intuitive?

It would, in principle, and was my first idea for naming this functionality. However, we use with... with very different semantics in ChangesOfVariables.jl, which will often be used in conjunction with InverseFunctions.jl. Having these different with...-functions closely together in code could be quite confusing to the reader.

How about addinverse instead of setinverse?

@aplavin
Copy link
Contributor

aplavin commented Sep 26, 2022

we use with... with very different semantics in ChangesOfVariables.jl

Interesting, if I understand correctly that package uses basically the opposite "direction" of with :)

How about addinverse instead of setinverse?

Well, with would also be consistent with FunctionWithInverse defined here...
I don't have a very strong preference here, choosing the right and general verb for such operations isn't obvious.

For example, Accessors uses "set" for setting something that already exists, and "insert" for adding a new component. Maybe, set isn't the worst choice here in the end?..
Btw, after this PR Accessors can define its set() method so that sin_with_inverse = @set inverse(sin) = asin works. Accessors already depends on InverseFunctions anyways. This is more obvious than sin_with_inverse = setinverse(sin, asin) in determining which argument is the function and which is the inverse.

@cscherrer
Copy link
Contributor

Interesting, if I understand correctly that package uses basically the opposite "direction" of with :)

FWIW, Zygote has something similar:

help?> Zygote.withgradient
  withgradient(f, args...)
  withgradient(f, ::Params)

  Returns both the value of the function and the gradient, as a named tuple.

  julia> y, ∇ = withgradient(/, 1, 2)
  (val = 0.5, grad = (0.5, -0.25))
  
  julia>== gradient(/, 1, 2)
  true

@oschulz
Copy link
Collaborator Author

oschulz commented Sep 26, 2022

FWIW, Zygote has something similar ... withgradient(f, args...)

Yes, that matches what ChangesOfVariables.with_logabsdet_jacobian(f, x) does in regard to "with" - it take the same inputs as f(x) but generates additional output. Whereas setinverse takes two functions and returns a "decorated" single function - that's why I'm hesitant to use withinverse for it.

@oschulz
Copy link
Collaborator Author

oschulz commented Sep 26, 2022

Btw, after this PR Accessors can define its set() method so that sin_with_inverse = @set inverse(sin) = asin works.

Oh, that's very neat! Maybe setinverse isn't that bad as a function name here then? Better than addinverse at least, right?

@aplavin aplavin mentioned this pull request Sep 26, 2022
@aplavin
Copy link
Contributor

aplavin commented Sep 26, 2022

Yes, maybe setinverse is actually fine.

Seems like with... can indeed be understood in the "opposite" way. I've only seen Base.withenv and MonteCarloMeasurements.with_nominal before, and they are more like withinverse(sin, asin) than the other meaning.

@oschulz
Copy link
Collaborator Author

oschulz commented Sep 26, 2022

Seems like with... can indeed be understood in the "opposite" way.

Right, like in #6 (thanks for the reminder there, @aplavin !).

@oschulz
Copy link
Collaborator Author

oschulz commented Sep 27, 2022

Are you happy with how this looks now, @devmotion ?

Copy link
Member

@devmotion devmotion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, I don't think the discussion in https://github.com/JuliaMath/InverseFunctions.jl/pull/25/files#r979044891 is blocking this PR.

@oschulz
Copy link
Collaborator Author

oschulz commented Sep 27, 2022

Thanks, I'll merge then?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Convenient way to specify/override the inverse of a function
4 participants