Skip to content
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

RuleBasedStateMachine is prone to Unsatisfiable errors #3618

Closed
levand opened this issue Apr 22, 2023 · 2 comments · Fixed by #3920
Closed

RuleBasedStateMachine is prone to Unsatisfiable errors #3618

levand opened this issue Apr 22, 2023 · 2 comments · Fixed by #3920
Labels
performance go faster! use less memory!

Comments

@levand
Copy link

levand commented Apr 22, 2023

A state machine frequently ends up as hypothesis.errors.Unsatisfiable when the input strategies to its rules themselves are frequently marked as invalid.

For example,

class MyStateMachine(RuleBasedStateMachine):

    @rule(data=st.lists(st.text(), min_size=5, unique=True))
    def rule1(self, data):
        assert data is not None


TestMyStateMachine = MyStateMachine.TestCase

Yields:

E   hypothesis.errors.Unsatisfiable: Unable to satisfy assumptions of run_state_machine

venv/lib/python3.10/site-packages/hypothesis/stateful.py:112: Unsatisfiable
--------------------------------------------------------------------------------------------------------- Hypothesis ---------------------------------------------------------------------------------------------------------
You can add @seed(187837441642656874040035655188699191288) to this test or run pytest with --hypothesis-seed=187837441642656874040035655188699191288 to reproduce this failure.
=================================================================================================== Hypothesis Statistics ====================================================================================================
myproj/test_hypothesis.py::TestMyStateMachine::runTest:

  - during generate phase (31.27 seconds):
    - Typical runtimes: ~ 0-55 ms, of which < 1ms in data generation
    - 0 passing examples, 0 failing examples, 1000 invalid examples
    - Events:
      * 56.80%, Retried draw from text().filter(not_yet_in_unique_list) to satisfy filter
      * 43.20%, Aborted test because unable to satisfy just(Rule(targets=(), function=rule1, arguments={'data': lists(text(), min_size=5, unique=True)}, preconditions=(), bundles=())).filter(RuleStrategy(machine=MyStateMachine({...})).is_valid).filter(lambda r: <unknown>)

  - Stopped because settings.max_examples=100, but < 10% of examples satisfied assumptions

This is the minimal example I could find, my actual state machine is much larger but exhibits the same error.

The state machine works fine when used with simpler or more reliable strategy. '

The st.lists(st.text(), min_size=5, unique=True) strategy also fine when used with @given (i.e. not in a state machine), although the stats show that it does frequently return invalid examples.

@levand levand changed the title RuleBasedStateMachine RuleBasedStateMachine is prone to Unsatisfiable errors Apr 22, 2023
@Zac-HD Zac-HD added the performance go faster! use less memory! label Apr 22, 2023
@levand
Copy link
Author

levand commented Apr 24, 2023

@Zac-HD I see why you tagged this performance but I do want to note that this is a pretty big obstacle to us being able to use state machines correctly.

In order to work around this issue, we need to make sure that all our composite strategies rarely or never mark examples as invalid; i.e, we basically cannot use assume or filter, or any of the built-in strategies that leverage filtering.

Specifically, we have to do the opposite of what the Hypothesis docs recommend for composite strategies: https://hypothesis.readthedocs.io/en/latest/data.html#composite-strategies. In the reimplementing_sets_strategy example, we specifically need to do things the "bad" way, since the "good" way means we run into this issue whenever we try to use the strategy in a state machine.

@Zac-HD
Copy link
Member

Zac-HD commented Mar 12, 2024

This turned out to be pretty simple in the end! I thought that #3894 might have helped, but it didn't at all - and at that point I was pretty confident that it wasn't actually due to filtering too much at all. Instead, it turned out to be trying to generate too much data; the fix is simply to stop taking additional steps if we've already generated 80% as much data as is possible. (we could tune it more precisely based on how many steps we've taken so far, but it's not really worth the trouble)

So why did avoiding filters seem to help? My best guess is that it's because your filter-free strategies (a) don't generate-and-discard when attempting to satisfy the filter, and (b) might generate smaller and simpler inputs overall. Happily, you'll now be able to use the same strategies across @given()-based and stateful testing 😁

HammadB pushed a commit to chroma-core/chroma that referenced this issue Jun 17, 2024
Hypothesis has made [many
improvements](https://github.com/HypothesisWorks/hypothesis/blob/master/hypothesis-python/docs/changes.rst)
in the last few months, including closing issues like
HypothesisWorks/hypothesis#3618.

Hoping that this will fix the recent error

> Data generation is extremely slow: Only produced 9 valid examples in
225.14 seconds (0 invalid ones and 744 exceeded maximum size). Try
decreasing size of the data you're generating (with e.g. max_size or
max_leaves parameters).


(https://github.com/chroma-core/chroma/actions/runs/9505770742/job/26201473178)

or at least provide a better place to start debugging from.

(Seems like this error may have started occurring after
#2297 was merged.)

Note: hypothesis was originally pegged in
#1760.
Anush008 pushed a commit to Anush008/chroma that referenced this issue Jun 27, 2024
Hypothesis has made [many
improvements](https://github.com/HypothesisWorks/hypothesis/blob/master/hypothesis-python/docs/changes.rst)
in the last few months, including closing issues like
HypothesisWorks/hypothesis#3618.

Hoping that this will fix the recent error

> Data generation is extremely slow: Only produced 9 valid examples in
225.14 seconds (0 invalid ones and 744 exceeded maximum size). Try
decreasing size of the data you're generating (with e.g. max_size or
max_leaves parameters).


(https://github.com/chroma-core/chroma/actions/runs/9505770742/job/26201473178)

or at least provide a better place to start debugging from.

(Seems like this error may have started occurring after
chroma-core#2297 was merged.)

Note: hypothesis was originally pegged in
chroma-core#1760.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance go faster! use less memory!
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants