egglog 12.0.0__cp313-cp313t-manylinux_2_17_ppc64.manylinux2014_ppc64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. egglog/__init__.py +13 -0
  2. egglog/bindings.cpython-313t-powerpc64-linux-gnu.so +0 -0
  3. egglog/bindings.pyi +887 -0
  4. egglog/builtins.py +1144 -0
  5. egglog/config.py +8 -0
  6. egglog/conversion.py +290 -0
  7. egglog/declarations.py +964 -0
  8. egglog/deconstruct.py +176 -0
  9. egglog/egraph.py +2247 -0
  10. egglog/egraph_state.py +978 -0
  11. egglog/examples/README.rst +5 -0
  12. egglog/examples/__init__.py +3 -0
  13. egglog/examples/bignum.py +32 -0
  14. egglog/examples/bool.py +38 -0
  15. egglog/examples/eqsat_basic.py +44 -0
  16. egglog/examples/fib.py +28 -0
  17. egglog/examples/higher_order_functions.py +42 -0
  18. egglog/examples/jointree.py +64 -0
  19. egglog/examples/lambda_.py +287 -0
  20. egglog/examples/matrix.py +175 -0
  21. egglog/examples/multiset.py +60 -0
  22. egglog/examples/ndarrays.py +144 -0
  23. egglog/examples/resolution.py +84 -0
  24. egglog/examples/schedule_demo.py +34 -0
  25. egglog/exp/MoA.ipynb +617 -0
  26. egglog/exp/__init__.py +3 -0
  27. egglog/exp/any_expr.py +947 -0
  28. egglog/exp/any_expr_example.ipynb +408 -0
  29. egglog/exp/array_api.py +2019 -0
  30. egglog/exp/array_api_jit.py +51 -0
  31. egglog/exp/array_api_loopnest.py +74 -0
  32. egglog/exp/array_api_numba.py +69 -0
  33. egglog/exp/array_api_program_gen.py +510 -0
  34. egglog/exp/program_gen.py +427 -0
  35. egglog/exp/siu_examples.py +32 -0
  36. egglog/ipython_magic.py +41 -0
  37. egglog/pretty.py +566 -0
  38. egglog/py.typed +0 -0
  39. egglog/runtime.py +888 -0
  40. egglog/thunk.py +97 -0
  41. egglog/type_constraint_solver.py +111 -0
  42. egglog/visualizer.css +1 -0
  43. egglog/visualizer.js +35798 -0
  44. egglog/visualizer_widget.py +39 -0
  45. egglog-12.0.0.dist-info/METADATA +93 -0
  46. egglog-12.0.0.dist-info/RECORD +48 -0
  47. egglog-12.0.0.dist-info/WHEEL +5 -0
  48. egglog-12.0.0.dist-info/licenses/LICENSE +21 -0
egglog/thunk.py ADDED
@@ -0,0 +1,97 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import TYPE_CHECKING, Generic, TypeVar
5
+
6
+ from typing_extensions import TypeVarTuple, Unpack
7
+
8
+ if TYPE_CHECKING:
9
+ from collections.abc import Callable
10
+
11
+
12
+ __all__ = ["Thunk", "split_thunk"]
13
+
14
+ T = TypeVar("T")
15
+ TS = TypeVarTuple("TS")
16
+ V = TypeVar("V")
17
+
18
+
19
+ def split_thunk(fn: Callable[[], tuple[T, V]]) -> tuple[Callable[[], T], Callable[[], V]]:
20
+ s = _Split(fn)
21
+ return s.left, s.right
22
+
23
+
24
+ @dataclass
25
+ class _Split(Generic[T, V]):
26
+ fn: Callable[[], tuple[T, V]]
27
+
28
+ def left(self) -> T:
29
+ return self.fn()[0]
30
+
31
+ def right(self) -> V:
32
+ return self.fn()[1]
33
+
34
+
35
+ @dataclass
36
+ class Thunk(Generic[T, *TS]):
37
+ """
38
+ Cached delayed function call.
39
+ """
40
+
41
+ state: Resolved[T] | Unresolved[T, *TS] | Resolving | Error
42
+
43
+ @classmethod
44
+ def fn(cls, fn: Callable[[Unpack[TS]], T], *args: *TS, context: str | None = None) -> Thunk[T, *TS]:
45
+ """
46
+ Create a thunk based on some functions and some partial args.
47
+
48
+ If the function is called while it is being resolved recursively it will raise an exception.
49
+ """
50
+ return cls(Unresolved(fn, args, context))
51
+
52
+ @classmethod
53
+ def value(cls, value: T) -> Thunk[T]:
54
+ return Thunk(Resolved(value))
55
+
56
+ def __call__(self) -> T:
57
+ match self.state:
58
+ case Resolved(value):
59
+ return value
60
+ case Unresolved(fn, args, context):
61
+ self.state = Resolving()
62
+ try:
63
+ res = fn(*args)
64
+ except Exception as e:
65
+ self.state = Error(e, context)
66
+ raise e from None
67
+ else:
68
+ self.state = Resolved(res)
69
+ return res
70
+ case Resolving():
71
+ msg = "Recursively resolving thunk"
72
+ raise ValueError(msg)
73
+ case Error(e):
74
+ raise e
75
+
76
+
77
+ @dataclass
78
+ class Resolved(Generic[T]):
79
+ value: T
80
+
81
+
82
+ @dataclass
83
+ class Unresolved(Generic[T, *TS]):
84
+ fn: Callable[[Unpack[TS]], T]
85
+ args: tuple[*TS]
86
+ context: str | None
87
+
88
+
89
+ @dataclass
90
+ class Resolving:
91
+ pass
92
+
93
+
94
+ @dataclass
95
+ class Error:
96
+ e: Exception
97
+ context: str | None
@@ -0,0 +1,111 @@
1
+ """Provides a class for solving type constraints."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections import defaultdict
6
+ from dataclasses import dataclass, field
7
+ from itertools import chain, repeat
8
+ from typing import TYPE_CHECKING, assert_never
9
+
10
+ from .declarations import *
11
+
12
+ if TYPE_CHECKING:
13
+ from collections.abc import Collection, Iterable
14
+
15
+
16
+ __all__ = ["TypeConstraintError", "TypeConstraintSolver"]
17
+
18
+
19
+ class TypeConstraintError(RuntimeError):
20
+ """Typing error when trying to infer the return type."""
21
+
22
+
23
+ @dataclass
24
+ class TypeConstraintSolver:
25
+ """
26
+ Given some typevars and types, solves the constraints to resolve the typevars.
27
+ """
28
+
29
+ _decls: Declarations = field(repr=False)
30
+ # Mapping of class ident to mapping of bound class typevar to type
31
+ _cls_typevar_index_to_type: defaultdict[Ident, dict[ClassTypeVarRef, JustTypeRef]] = field(
32
+ default_factory=lambda: defaultdict(dict)
33
+ )
34
+
35
+ def bind_class(self, ref: JustTypeRef) -> None:
36
+ """
37
+ Bind the typevars of a class to the given types.
38
+ Used for a situation like Map[int, str].create().
39
+ """
40
+ name = ref.ident
41
+ cls_typevars = self._decls.get_class_decl(name).type_vars
42
+ if len(cls_typevars) != len(ref.args):
43
+ raise TypeConstraintError(f"Mismatch of typevars {cls_typevars} and {ref}")
44
+ bound_typevars = self._cls_typevar_index_to_type[name]
45
+ for i, arg in enumerate(ref.args):
46
+ bound_typevars[cls_typevars[i]] = arg
47
+
48
+ def infer_arg_types(
49
+ self,
50
+ fn_args: Collection[TypeOrVarRef],
51
+ fn_return: TypeOrVarRef,
52
+ fn_var_args: TypeOrVarRef | None,
53
+ return_: JustTypeRef,
54
+ cls_ident: Ident | None,
55
+ ) -> tuple[Iterable[JustTypeRef], tuple[JustTypeRef, ...]]:
56
+ """
57
+ Given a return type, infer the argument types. If there is a variable arg, it returns an infinite iterable.
58
+
59
+ Also returns the bound type params if the class name is passed in.
60
+ """
61
+ self.infer_typevars(fn_return, return_, cls_ident)
62
+ arg_types: Iterable[JustTypeRef] = [self.substitute_typevars(a, cls_ident) for a in fn_args]
63
+ if fn_var_args:
64
+ # Need to be generator so it can be infinite for variable args
65
+ arg_types = chain(arg_types, repeat(self.substitute_typevars(fn_var_args, cls_ident)))
66
+ bound_typevars = (
67
+ tuple(
68
+ v
69
+ # Sort by the index of the typevar in the class
70
+ for _, v in sorted(
71
+ self._cls_typevar_index_to_type[cls_ident].items(),
72
+ key=lambda kv: self._decls.get_class_decl(cls_ident).type_vars.index(kv[0]),
73
+ )
74
+ )
75
+ if cls_ident
76
+ else ()
77
+ )
78
+ return arg_types, bound_typevars
79
+
80
+ def infer_typevars(self, fn_arg: TypeOrVarRef, arg: JustTypeRef, cls_ident: Ident | None = None) -> None:
81
+ match fn_arg:
82
+ case TypeRefWithVars(cls_ident, fn_args):
83
+ if cls_ident != arg.ident:
84
+ raise TypeConstraintError(f"Expected {cls_ident}, got {arg.ident}")
85
+ for inner_fn_arg, inner_arg in zip(fn_args, arg.args, strict=True):
86
+ self.infer_typevars(inner_fn_arg, inner_arg, cls_ident)
87
+ case ClassTypeVarRef():
88
+ if cls_ident is None:
89
+ msg = "Cannot infer typevar without class name"
90
+ raise RuntimeError(msg)
91
+
92
+ class_typevars = self._cls_typevar_index_to_type[cls_ident]
93
+ if fn_arg in class_typevars:
94
+ if class_typevars[fn_arg] != arg:
95
+ raise TypeConstraintError(f"Expected {class_typevars[fn_arg]}, got {arg}")
96
+ else:
97
+ class_typevars[fn_arg] = arg
98
+ case _:
99
+ assert_never(fn_arg)
100
+
101
+ def substitute_typevars(self, tp: TypeOrVarRef, cls_ident: Ident | None = None) -> JustTypeRef:
102
+ match tp:
103
+ case ClassTypeVarRef():
104
+ assert cls_ident is not None
105
+ try:
106
+ return self._cls_typevar_index_to_type[cls_ident][tp]
107
+ except KeyError as e:
108
+ raise TypeConstraintError(f"Not enough bound typevars for {tp!r} in class {cls_ident}") from e
109
+ case TypeRefWithVars(name, args):
110
+ return JustTypeRef(name, tuple(self.substitute_typevars(arg, cls_ident) for arg in args))
111
+ assert_never(tp)