Skip to content

Commit d244b75

Browse files
authored
refactor(common): consolidate egraph implementation by using FrozenSlotted (ibis-project#8702)
1 parent 467f688 commit d244b75

1 file changed

Lines changed: 8 additions & 36 deletions

File tree

ibis/common/egraph.py

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from collections.abc import Callable, Hashable, Iterable, Iterator, Mapping
77
from typing import Any, TypeVar
88

9+
from ibis.common.bases import FrozenSlotted as Slotted
910
from ibis.common.graph import Node
1011
from ibis.util import promote_list
1112

@@ -258,38 +259,6 @@ def verify(self):
258259
)
259260

260261

261-
class Slotted:
262-
"""A lightweight alternative to `ibis.common.grounds.Concrete`.
263-
264-
This class is used to create immutable dataclasses with slots and a precomputed
265-
hash value for quicker dictionary lookups.
266-
"""
267-
268-
__slots__ = ("__precomputed_hash__",)
269-
__precomputed_hash__: int
270-
271-
def __init__(self, *args):
272-
for name, value in itertools.zip_longest(self.__slots__, args):
273-
object.__setattr__(self, name, value)
274-
object.__setattr__(self, "__precomputed_hash__", hash(args))
275-
276-
def __eq__(self, other):
277-
if self is other:
278-
return True
279-
if type(self) is not type(other):
280-
return NotImplemented
281-
for name in self.__slots__:
282-
if getattr(self, name) != getattr(other, name):
283-
return False
284-
return True
285-
286-
def __hash__(self):
287-
return self.__precomputed_hash__
288-
289-
def __setattr__(self, name, value):
290-
raise AttributeError("Can't set attributes on immutable ENode instance")
291-
292-
293262
class Variable(Slotted):
294263
"""A named capture in a pattern.
295264
@@ -306,7 +275,7 @@ class Variable(Slotted):
306275
def __init__(self, name: str):
307276
if name is None:
308277
raise ValueError("Variable name cannot be None")
309-
super().__init__(name)
278+
super().__init__(name=name)
310279

311280
def __repr__(self):
312281
return f"${self.name}"
@@ -360,7 +329,7 @@ class Pattern(Slotted):
360329
def __init__(self, head, args, name=None, conditions=None):
361330
# TODO(kszucs): ensure that args are either patterns, variables or leaf values
362331
assert all(not isinstance(arg, (ENode, Node)) for arg in args)
363-
super().__init__(head, tuple(args), name)
332+
super().__init__(head=head, args=tuple(args), name=name)
364333

365334
def matches_none(self):
366335
"""Evaluate whether the pattern is guaranteed to match nothing.
@@ -472,6 +441,9 @@ class DynamicApplier(Slotted):
472441
__slots__ = ("func",)
473442
func: Callable
474443

444+
def __init__(self, func):
445+
super().__init__(func=func)
446+
475447
def substitute(self, egraph, enode, subst):
476448
kwargs = {k: v for k, v in subst.items() if isinstance(k, str)}
477449
result = self.func(egraph, enode, **kwargs)
@@ -494,7 +466,7 @@ def __init__(self, matcher, applier):
494466
raise TypeError(
495467
"applier must be a Pattern or a Variable returning an ENode"
496468
)
497-
super().__init__(matcher, applier)
469+
super().__init__(matcher=matcher, applier=applier)
498470

499471
def __repr__(self):
500472
return f"{self.lhs} >> {self.rhs}"
@@ -519,7 +491,7 @@ class ENode(Slotted, Node):
519491
def __init__(self, head, args):
520492
# TODO(kszucs): ensure that it is a ground term, this check should be removed
521493
assert all(not isinstance(arg, (Pattern, Variable)) for arg in args)
522-
super().__init__(head, tuple(args))
494+
super().__init__(head=head, args=tuple(args))
523495

524496
@property
525497
def __argnames__(self):

0 commit comments

Comments
 (0)