-
Notifications
You must be signed in to change notification settings - Fork 38
Add rules for LogExpFunctions #69
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
Conversation
|
||
# unary | ||
@define_diffrule LogExpFunctions.xlogx(x) = :(1 + log($x)) | ||
@define_diffrule LogExpFunctions.logistic(x) = :(z = LogExpFunctions.logistic($x); z * (1 - z)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I missed it but it seems there is no way to reuse the result of the primal computation in DiffRules?
if "mod2pi" == string($M.$f) | ||
goo = 4pi + $modifier | ||
@test NaN === $deriv | ||
let |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added the let
blocks to fix some local/global scope warnings.
Codecov Report
@@ Coverage Diff @@
## master #69 +/- ##
==========================================
+ Coverage 93.75% 94.66% +0.91%
==========================================
Files 2 2
Lines 128 150 +22
==========================================
+ Hits 120 142 +22
Misses 8 8
Continue to review full report at Codecov.
|
@DilumAluthge Is the |
Hmmm. I'm not very familiar with that particular job. Who wrote the original workflow file? Maybe @ChrisRackauckas will know. |
No, it works just fine. It correctly shows that this PR breaks all downstream packages. As explained above, the problem is not that this change is technically breaking but that downstream packages don't use the output of |
I somehow misunderstood your original comment even though the issue is pretty well explained there. What about updating all the downstream packages before merging this? |
Another option might be to let the caller specify which modules to cover, and set a default which matches the old behaviour: |
I like this suggestion, I'll update the PR (I'll use a tuple as default value to save some allocations though I think). |
The test failure with nightly is unrelated and caused by an instability of the finite differencing method for the randomly chosen values (due to the RNG changes and the possibly different order of the rules they are not stable across different Julia versions). Maybe in a separate PR one could switch to more advanced methods eg by using FiniteDifferences. |
Bump 🙂 I changed this PR according to the suggestions such that it is not breaking anymore but only a deprecation warning is shown that in the next breaking release the behaviour will change and not only rules for Base, SpecialFunctions, and NaNMath but all available rules will be returned by |
Bump 🙂 |
Is it intended that all the workflow changes are part of this PR? I'd think that they belong in a separate PR. (Btw I don't think we should be using the git based registry). |
Partly. I updated the Julia version in the docs action, updated Additionally, I added the "cancel actions for old commits" feature on purpose since otherwise GH actions would be blocked by the longer running integration tests. I'll move the TagBot + CompatHelper updates to a separate PR though, they are unrelated. |
I moved the CI updates to #70. |
@@ -1,7 +1,5 @@ | |||
name: TagBot | |||
on: | |||
schedule: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andreasnoack I forgot to remove these lines in #70, seems I copied the updated file incorrectly. schedule:
is not needed anymore, so removing this trigger will reduce the amount of runs.
All other CI changes were addressed in #70.
This would have been my preference. Arguably the downstream packages are mis-using the API. For packages that are this deep in the dependency tree, we should try to avoid introducing deprecation warnings that users see (we don't want JuMP users seeing deprecation warnings in production or during their tests that they can't do anything about). Another option would have been to make accessing all the rules opt-in so |
Users don't see deprecation warnings since they are not enabled by default. And arguably in tests we want downstream packages to see deprecation warnings - they don't have to fix them immediately but they are notified that the API will change in the future and have time to prepare a fix. |
I can understand that you would like that deprecation warnings don't show for users, and apparently also in tests. However, I think the whole point of deprecation warnings is to clearly mark the API as deprecated and notify packages and users about this future change such that they can react accordingly (if they plan to support a future breaking release). In my opinion, deprecation warnings are no errors that have to be fixed immediately since they are no errors but warnings or notifications. It would basically be impossible for packages with many, possibly indirect, dependencies to mark something as deprecated if one had to fix all downstream packages first. And in my opinion this would also invalidate the reason for deprecation warnings. I don't think it can be expected from contributors to fix the use of |
I didn't know it was only introduced in more recent versions. Of course, you can always disable them manually with |
I think I missed this at the time, but why must this add a dependence on LogExpFunctions? And hence on 6 other packages. I mean a test-time dep is fine, and a compat entry in Project.toml is fine (like SpecialFunctions) but why actually load it? |
Not all functions are defined in all versions of LogExpFunctions, and it is not possible to check for their existence in any other way than with It does not affect dependencies of DiffRule since SpecialFunctions depends on LogExpFunctions and hence it's an indirect dependency anyway. Moreover, it is very lightweight and all its dependencies are very lightweight (only interfaces such as ChainRulesCore, InverseFunctions, and ChangesOfVariables). It was extracted from StatsFuns to make it so lightweight (in particular without Rmath) that it can be added to any package without major impacts on package load times and deoendencies. |
But if LogExpFunctions follows semver, then surely we can just bound the version. Removing them is a breaking change. This is exactly how SpecialFunctions was handled.
But this package doesn't depend on SpecialFunctions, except to bound its version. That's the pattern I'm suggesting could be copied. This package did and (I think) still can have zero dependencies. That's the best situation, and I think we ought to have a solid reason to move away from it. The costs of doing so aren't huge, but they aren't nothing either. It seems brittle to have every little package depend on every other one, e.g. the fairly recent case where some change broke Static.jl and about a thousand downstream packages. |
This PR adds the rules for the functions in LogExpFunctions, as defined in https://github.com/JuliaStats/LogExpFunctions.jl/blob/master/src/chainrules.jl.
The motivation for adding them here is that recent versions of SpecialFunctions depend on LogExpFunctions. Hence LogExpFunctions is already an indirect dependency of DiffRules. Moreover, if AD backends such as ForwardDiff, Tracker, and ReverseDiff are fixed (see below) this PR fixes remaining test issues for these backends in DistributionsAD (see TuringLang/DistributionsAD.jl#203).
While this PR is not breaking technically, it seems it breaks almost all downstream dependencies in practice. The reason is that it seems to be common practice to iterate over
DiffRules.diffrules()
and define differentiation rules with@eval
without checking that the module where the function is defined is available in the current module. I.e., they are all missing a check such asM in (:Base, :SpecialFunctions, :NaNMath)
to ensure that they don't try to define rules for unsupported packages. I guess this means that we should update the version number to DIffRules 2.0.0 to make sure that we don't break downstream packages. When upgrading to DiffRules 2.0.0, ideally the packages fix this bug.Additionally, one could provide something like
to make it more convenient for packages to load rules for all modules that are loaded in the invoking module.