-
-
Notifications
You must be signed in to change notification settings - Fork 121
Callback bug fixes #574
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
Callback bug fixes #574
Conversation
| iter = 1 | ||
| while sign(zero_func(bottom_t)) == sign_top && iter < 12 | ||
| # This check should match the same check in bisection | ||
| while sign(zero_func(bottom_t)) * sign_top >= zero(sign_top) && iter < 12 |
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.
This is probably one of the issues I was looking for..
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.
yeah, this is one of those things where it's like... huh, yeah... that's umm... wow how did anything ever work before? 😆
|
|
||
| sign_top = sign(zero_func(top_t)) | ||
| diff_t = integrator.tdir * 2eps(typeof(bottom_t)) | ||
| diff_t = integrator.tdir * 2eps(bottom_t) |
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.
@ChrisRackauckas I am not good with eps, but should this be okay? I think this would be okay
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.
yes, this is much better. I didn't catch this before, but you almost never want to do eps(typeof(t)) and always eps(t) since floating point is relative.
|
@pengwyn thank you so much for your contribution! I agree with all 3 of the points you made.
Awesome! I assume your code works well with these changes too. |
| iter = 1 | ||
| while sign(zero_func(bottom_t)) == sign_top && iter < 12 | ||
| # This check should match the same check in bisection | ||
| while sign(zero_func(bottom_t)) * sign_top >= zero(sign_top) && iter < 12 |
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 computing zero(sign_top) before the loop would be slightly more efficient.
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.
Shouldn't this be inlined by the compiler? Not that it is hard to move it outside the loop, but it is slightly less readable. Actually to contradict myself, I ran @code_warntype on it and it couldn't infer the result of zero_func.
Originally I thought that this duplicated check (between bisection and find_callback_time) would be best represented once as a function like:
different_sign(x::T,y::T) = sign(x) * sign(y) >= zero(T)However, this wouldn't work in the scenario of Unitful quantities (there's a bit of asymmetry there between zero(x), one(x) and oneunit(x)). But this would work:
different_sign(x::T,y::T) = sign(x) * sign(y) >= zero(sign(x))as long as zero(sign(x)) is inlined and the sign(x) calculation elided.
Alternatively, it could be argued that sign(x) is always one of [0, +1, -1] and so we could put directly:
different_sign(x::T,y::T) = sign(x) * sign(y) >= 0There 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 just realised that was a brain dump and not a proper reply. My question is should I a) keep the same style (and move the zero(..) out of the for loop)? or b) turn it into a separate function and put that into both find_callback_time and bisection?
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.
Actually to contradict myself, I ran @code_warntype on it and it couldn't infer the result of zero_func.
Oh no, how come?
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.
It turned out to be 3 bugs, one in my external code and two more in the callbacks.jl file. I'll open another pull request about them.
| iter = 1 | ||
| while sign(zero_func(bottom_t)) == sign_top && iter < 12 | ||
| # This check should match the same check in bisection | ||
| while sign(zero_func(bottom_t)) * sign_top >= zero(sign_top) && iter < 12 |
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.
Same here, maybe one could move zero(sign_top) out of the loop.
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.
IIRC LLVM usually will handle this case if it's type-stable.
@kanav99 I'm glad you find it useful! I hope it helps with #564 too.
Yeap, it's hitting the right benchmarks in my physics problem on everything I've tried so far! |
|
We should check how many of https://github.com/SciML/DifferentialEquations.jl/labels/callbacks are fixed by this, and get tests on them. I assume that the fix of making the |
In using VectorContinuousCallback in my code I came across several bugs, leading to exceptions, which I think I've fixed here.
integrator.vector_event_last_time == event_idxcompared an Int to a Vector{Int} so it would always be false. I think it should beidxinstead ofevent_idx.diff_tused in the nudging of the bottom t to find a different sign for bottom and top was using machine epsilon of the type, not the actual time. In my particular case, t was very large causing this to fail.find_callback_timeandbisectionwas inconsistent. The nudger infind_callback_timewas happy with a zero value for bottom_t, butbisectionwanted a non-zero value.I wanted to write some tests for this but ran out of time and figured that these are simple enough fixes. All the existing tests of
DiffEqBaseandOrdinaryDiffEqpass on my machine.