Skip to content

Integer shrinking is less efficient than it could be. #735

@jonaskoelker

Description

@jonaskoelker

See https://gist.github.com/jonaskoelker/4390fcc8bec868cd3b4f4ef43f29b830, in particular in run the sbt command testOnly DefaultShrinking -- -f triple and testOnly FancyShrinking -- -f triple to compare.

The current shrinking shrinks n to n/2, n/4, n/8, ..., interleaved with the negation of this stream. Ideally (I guess?) the shrinking process does a binary search for the smallest failing value. However, given that shrinking is restarted every time a failing example is found, the tail of the shrink stream is only looked at if running the test on the first shrink succeeds.

Thus, if we want to approximate a binary search, we can use the knowledge that prior shrinks succeeded to decide the next shrunk. In particular, I think 0, n - n/2, n - n/4, n - n/8, ... is a better stream of candidates (for positive n): it repeatedly bisects a range which is known to contain a boundary case until the next failure is found, at which point it repeats this effective search for a boundary value. (This is also, perhaps approximately, the integral-type shrinking used in rust-quickcheck.)

If you run the commands I mentioned above, you will see that my suggested shrinking reduces the failing example in fewer shrinks (easy to eyeball for small values of n) than the current built-in shrinker.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions