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
Boundary of search space on pairs of floats is reliably limited #2671
Comments
I think this might be related to our zero-blocks heuristics? @DRMacIver or @Zalathar can probably say more. |
I had a brief look into this, and the impression I have so far is that our strategy for bounded floats doesn't have any explicit bias towards zeros (unlike the unbounded-floats strategy). And since Conjecture currently doesn't go out of its way to generate low-level zeros (IIRC), the end result is that zeros end up being astronomically rare outside of the guaranteed all-zeros example. (I haven't yet investigated what's going on behind the skew towards one axis working and the other axis not working.) |
Hmm, probably related to #1704 then - in that we may want to reengineer the bounded floats strategy. |
Sorry, just saw your statement in parenthesis |
OK, I believe the observed asymmetry happens as a side-effect of #2523. After generating a novel prefix, the engine first tries zero-extending it, to get an estimate of how long a “short” example should be. In the case of two bounded-float arguments, this process is pretty much guaranteed to generate a non-minimal value for the first, and a minimal value for the second. This matches my observation that the (correctly) reliably-failing test would always fail on its second example (i.e. the first one after the all-zeros example). (Aside: I managed to greatly confuse myself by assuming that Hypothesis generates argument values in left-to-right program order, which turns out to not be the case in general. Something to keep an eye on when doing this sort of low-level detective work.) |
I think a good general solution to this would be to add another mutation pass. Currently we just try to duplicate segments (causing the bright diagonal line in @rsokl's figure above), but shuffling equivalent segments would also make sense - albeit probably with different heuristics about when to stop. |
There were two things that I had vaguely intended to do about this, but never ended up prioritizing:
For the latter, my understanding is that David mostly removed them in the spirit of “let's rip out some annoying complexity and see if we get away with it”. So if this issue constitutes evidence that we didn't actually get away with it, then it would make sense to thoughtfully bring some of them back. |
Sounds good!
I'm actually planning out a #2878-style merging of our bounded and unbounded floating-point strategies, with the intent of improving the distribution and shrinking behaviour - especially for 32bit and 16bit floats where rejection sampling is hilariously inefficient.
I'm interested in building mutators which work for very long runs (~millions of test cases) without e.g. blowing through memory limits, to use in HypoFuzz, including many ideas which don't 'pay for their overhead' in Hypothesis' typically short runs. Agreed that the biased-random tricks might be worth bringing back though. |
Fixed by #3327 - we now add the |
Generating a pair of floats with
@given(x=st.floats(x_min, x_max), y=st.floats(y_min, y_max))
fails to ever generate cases along the "vertical strip"(x_min, y)
, other than the point(x_min, y_min)
.This is not true for the transpose – the "horizontal strip"
(x, y_min)
is explored in a robust way.The following tests demonstrate this:
I found this because I noticed that a test that I had written should have been failing along
(x_min, y)
other than at(x_min, y_min)
, but it never did. I was surprised that simply swapping the order of my parameters got the test to fail.The text was updated successfully, but these errors were encountered: