When a fuel parameter of more than 3 is supplied to a constrained numerator derived from an inductive relation (i.e. an instance of the EnumSizedSuchThat typeclass), we encounter a stack overflow issue.
See Test/DeriveEnumSuchThat/DerivePermutationEnumerator.lean for an example. To run the enumerator, you can do the following:
def l' := [1, 2, 3]
-- This prints out `[some [2, 1, 3], some [1, 3, 2], ...]`
-- However, changing `size` to 3 causes stack overflow
#eval runSizedEnum (EnumSizedSuchThat.enumSizedST (fun l => Permutation l l') (size := 2)
Right now, the implementation of lazy lists (see LazyList.lean), which underpin enumerators, follows the QuickChick source code very closely, although I am not entirely sure what is the origin of this bug. I wonder if switching to a (thunked) representation based on Haskell's difference lists will address this issue, since enumerators use LazyLists under append-heavy workloads, and difference lists support amortized O(1) append operations.
As a temporary workaround, when a derived checker invokes a constrained enumerator (e.g. for existentially quantified variables), we pass in (min 2 initSize) as the fuel for the enumerator in the derived checker code -- see this PR for details.
When a fuel parameter of more than 3 is supplied to a constrained numerator derived from an inductive relation (i.e. an instance of the
EnumSizedSuchThattypeclass), we encounter a stack overflow issue.See
Test/DeriveEnumSuchThat/DerivePermutationEnumerator.leanfor an example. To run the enumerator, you can do the following:Right now, the implementation of lazy lists (see
LazyList.lean), which underpin enumerators, follows the QuickChick source code very closely, although I am not entirely sure what is the origin of this bug. I wonder if switching to a (thunked) representation based on Haskell's difference lists will address this issue, since enumerators useLazyLists under append-heavy workloads, and difference lists support amortized O(1) append operations.As a temporary workaround, when a derived checker invokes a constrained enumerator (e.g. for existentially quantified variables), we pass in
(min 2 initSize)as the fuel for the enumerator in the derived checker code -- see this PR for details.