Closed jmid closed 10 months ago
Rebased on main
after having merged #282
Another possibility would be:
if (try x <> y with Invalid_argument _ -> x != y) then ...
Ha! That's an interesting suggestion... As you pointed out off-line, that however has a different worst case complexity.
To better understand, I tried the suggestion and reran the test suite to spot which other optimizations it would pick up and report as expect-test and unit-test failures. The result was a none however. This indicates a test suite short-coming, as it should make a difference when shrinking heap allocated data, say [1L; 1L; 1L; 1L; ...]
.
I also reran the shrinker benchmark (details in unfolding below):
main
Overall
main
(0.907s vs 0.911s)bind list_size constant
, i.e., 10% (230-207/230)lists shorter than 432
, i.e., 8% (20737 - 19018/20737)lists shorter than 10
, i.e., 10-11%:
iteration seed 1234 iteration seed 8743 iteration seed 6789 total
Shrink test name Q1/s #succ/#att Q2/s #succ/#att Q1/s #succ/#att Q2/s #succ/#att Q1/s #succ/#att Q2/s #succ/#att Q1/s Q2/s
< bind list_size constant 0.000 52/230 0.000 12/25 0.000 49/227 0.000 9/19 0.000 43/192 0.000 10/19 0.000 0.000
< lists shorter than 10 0.000 49/315 0.000 15/24 0.000 50/315 0.000 17/34 0.000 36/236 0.000 13/28 0.000 0.000
< lists shorter than 432 0.184 1738/20737 0.738 413/448 0.100 1667/19905 0.312 419/461 0.185 1712/20417 0.686 422/471 0.470 1.736
---
> bind list_size constant 0.000 52/207 0.000 12/25 0.000 49/204 0.000 9/19 0.000 43/171 0.000 10/19 0.000 0.000
> lists shorter than 10 0.000 49/279 0.000 15/24 0.000 50/282 0.000 17/34 0.000 36/210 0.000 13/28 0.000 0.000
> lists shorter than 432 0.178 1738/19018 0.739 413/448 0.104 1667/18254 0.287 419/461 0.187 1712/18727 0.661 422/471 0.469 1.687
As such, I lean towards going with the proposed change for now as it gets us a nice improvement on some list shrinking situations at an affordable complexity.
On second thought, there's something nice about the shrinker avoiding redundant candidates equally well on unboxed and boxed data types without an end-user having to worry about the difference.
Generally I would expect a property to be more costly than a =
(or <>
) test over input data, and thus that it would be worthwhile to trade the latter for the former.
I've just added 3 commits:
Shrink.list_spine
behaviourInvalid_argument "compare: functional value"
exception
This little PR reintroduces a small optimization to
Shrink.list_spine
that had to be rolled back in #280. The reason was that the polymorphic difference (inequality?) operator<>
would fail when comparing list elements with function values:Kudos to @shym for suggesting a simple fix: use an address comparison
!=
instead!On the one hand this
test_list_spine_compare
On the other hand, it doesn't identify as many equalities since, e.g., identical strings don't necessarily live at the same address :shrug: