diff --git a/src/icepool/evaluator/expression.py b/src/icepool/evaluator/expression.py index 3e91b723..cbe86778 100644 --- a/src/icepool/evaluator/expression.py +++ b/src/icepool/evaluator/expression.py @@ -36,6 +36,7 @@ def __init__(self, unbound_expressions.append(unbound_expression) self._expressions = tuple(unbound_expressions) self._truth_value = truth_value + raise NotImplementedError() def next_state(self, state, outcome, *counts): if state is None: diff --git a/src/icepool/multiset_expression.py b/src/icepool/multiset_expression.py index 78b141e3..ed6917c8 100644 --- a/src/icepool/multiset_expression.py +++ b/src/icepool/multiset_expression.py @@ -237,8 +237,8 @@ def _hash_key(self) -> Hashable: Used to implement `equals()` and `__hash__()` """ - return (self._local_hash_key, ) + tuple(child._hash_key - for child in self._children) + return (self._local_hash_key, + tuple(child._hash_key for child in self._children)) def equals(self, other) -> bool: """Whether this expression is logically equal to another object.""" @@ -251,6 +251,7 @@ def _hash(self) -> int: return hash(self._hash_key) def __hash__(self) -> int: + print(self._hash_key) return self._hash def _iter_nodes(self) -> 'Iterator[MultisetExpression]': @@ -978,9 +979,7 @@ def evaluate( A `Die` if the expression is are fully bound. A `MultisetEvaluator` otherwise. """ - if all( - isinstance(expression, icepool.MultisetGenerator) - for expression in expressions): + if all(expression._free_arity() == 0 for expression in expressions): return evaluator.evaluate(*expressions) evaluator = icepool.evaluator.ExpressionEvaluator(*expressions, evaluator=evaluator) diff --git a/src/icepool/multiset_function.py b/src/icepool/multiset_function.py index f0617487..f75c37c3 100644 --- a/src/icepool/multiset_function.py +++ b/src/icepool/multiset_function.py @@ -118,6 +118,7 @@ def bad(a, b) output an evaluator or a nested tuple of evaluators. Tuples will result in a `JointEvaluator`. """ + raise NotImplementedError() parameters = inspect.signature(function, follow_wrapped=False).parameters for parameter in parameters.values(): if parameter.kind not in [ diff --git a/src/icepool/multiset_variable.py b/src/icepool/multiset_variable.py index da1b27cc..da158115 100644 --- a/src/icepool/multiset_variable.py +++ b/src/icepool/multiset_variable.py @@ -53,6 +53,7 @@ def denominator(self) -> int: def _unbind(self, next_index: int) -> 'tuple[MultisetExpression, int]': return self, next_index + @property def _local_hash_key(self) -> Hashable: return (MultisetVariable, self._index) diff --git a/src/icepool/operator/adjust_counts.py b/src/icepool/operator/adjust_counts.py index 5f402a12..57ee8739 100644 --- a/src/icepool/operator/adjust_counts.py +++ b/src/icepool/operator/adjust_counts.py @@ -45,6 +45,7 @@ def _transform_next( def local_order(self) -> Order: return Order.Any + @property def _local_hash_key(self) -> Hashable: return MultisetMapCounts, self._function @@ -75,6 +76,7 @@ def _transform_next( def local_order(self) -> Order: return Order.Any + @property def _local_hash_key(self) -> Hashable: return type(self), self._constant @@ -164,6 +166,7 @@ def _transform_next( def local_order(self) -> Order: return Order.Any + @property def _local_hash_key(self) -> Hashable: return MultisetKeepCounts, self._constant diff --git a/src/icepool/operator/binary.py b/src/icepool/operator/binary.py index 965a8f56..ddd763f8 100644 --- a/src/icepool/operator/binary.py +++ b/src/icepool/operator/binary.py @@ -52,6 +52,7 @@ def _transform_next( def local_order(self) -> Order: return Order.Any + @property def _local_hash_key(self) -> Hashable: return type(self) diff --git a/src/icepool/operator/filter_outcomes.py b/src/icepool/operator/filter_outcomes.py index 469439ae..d0d3a74d 100644 --- a/src/icepool/operator/filter_outcomes.py +++ b/src/icepool/operator/filter_outcomes.py @@ -71,6 +71,7 @@ def _transform_next( def local_order(self) -> Order: return Order.Any + @property def _local_hash_key(self) -> Hashable: return MultisetFilterOutcomes, self._func, self._invert @@ -127,6 +128,7 @@ def _transform_next( def local_order(self) -> Order: return Order.Any + @property def _local_hash_key(self) -> Hashable: return MultisetFilterOutcomesBinary, self._invert diff --git a/src/icepool/operator/keep.py b/src/icepool/operator/keep.py index ae94653c..ecc52f79 100644 --- a/src/icepool/operator/keep.py +++ b/src/icepool/operator/keep.py @@ -151,6 +151,7 @@ def _transform_next( def local_order(self) -> Order: return self._keep_order + @property def _local_hash_key(self) -> Hashable: return self._keep_order, self._keep_tuple, self._drop diff --git a/src/icepool/operator/match.py b/src/icepool/operator/match.py index bec3e9c4..8a344acd 100644 --- a/src/icepool/operator/match.py +++ b/src/icepool/operator/match.py @@ -78,6 +78,7 @@ def _transform_next( def local_order(self) -> Order: return self._order + @property def _local_hash_key(self) -> Hashable: return (MultisetSortMatch, self._order, self._tie, self._left_first, self._right_first, self._left_lead) @@ -134,6 +135,7 @@ def _transform_next( def local_order(self) -> Order: return self._order + @property def _local_hash_key(self) -> Hashable: return (MultisetMaximumMatch, self._order, self._match_equal, self._keep, self._prev_matchable) diff --git a/src/icepool/operator/multiset_operator.py b/src/icepool/operator/multiset_operator.py index 220ce469..061d764c 100644 --- a/src/icepool/operator/multiset_operator.py +++ b/src/icepool/operator/multiset_operator.py @@ -67,14 +67,16 @@ def _generate_min(self, min_outcome: T) -> PopMultisetGeneration: for t in itertools.product(*(child._generate_min(min_outcome) for child in self._children)): new_children, counts, weights = zip(*t) + counts = tuple(c[0] for c in counts) next_self, count = self._transform_next(new_children, min_outcome, counts) yield next_self, (count, ), math.prod(weights) def _generate_max(self, max_outcome: T) -> PopMultisetGeneration: - for t in itertools.product(*(child._generate_min(max_outcome) + for t in itertools.product(*(child._generate_max(max_outcome) for child in self._children)): new_children, counts, weights = zip(*t) + counts = tuple(c[0] for c in counts) next_self, count = self._transform_next(new_children, max_outcome, counts) yield next_self, (count, ), math.prod(weights) @@ -95,5 +97,5 @@ def _unbind(self, next_index: int) -> 'tuple[MultisetExpression, int]': for child in self._children: unbound_child, next_index = child._unbind(next_index) unbound_children.append(unbound_child) - unbound_expression = self._copy(unbound_children) + unbound_expression = self._copy(tuple(unbound_children)) return unbound_expression, next_index