{ "cells": [ { "cell_type": "markdown", "id": "7fb27b941602401d91542211134fc71a", "metadata": {}, "source": [ "```{post} 2023-07-20\n", ":author: Saul\n", "```\n" ] }, { "cell_type": "markdown", "id": "a611c138-1afd-4d6f-9578-4f358d2438eb", "metadata": { "editable": true, "slideshow": { "slide_type": "skip" }, "tags": [] }, "source": [ "```{eval-rst}\n", "`Presentation as HTML <../2023_07_presentation.slides.html>`_\n", "```\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "acae54e37e7d407bbb7b55eff062a284", "metadata": {}, "outputs": [ { "data": { "image/jpeg": "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", "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import YouTubeVideo\n", "\n", "YouTubeVideo(\"Pbi2uV9vWPg\")" ] }, { "attachments": {}, "cell_type": "markdown", "id": "68dd13a3-5864-4764-a528-1eedac698723", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "# EGraphs in Python\n", "\n", "- Overview of the ecosystem\n", "- What is an e-graph?\n", "- What is egglog?\n", "- What are some possible applications in the PyData world?\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "1f7b1c58-0f6f-4d43-a8b0-c04b5d2f5b08", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [ "remove-input" ] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_6\n", "\n", "\n", "cluster_6\n", "\n", "\n", "\n", "outer_cluster_9\n", "\n", "\n", "cluster_9\n", "\n", "\n", "\n", "outer_cluster_py_ndarray_12463696466920899969_0\n", "\n", "\n", "cluster_py_ndarray_12463696466920899969_0\n", "\n", "\n", "\n", "outer_cluster_py_value_8004441328793213481_0\n", "\n", "\n", "cluster_py_value_8004441328793213481_0\n", "\n", "\n", "\n", "outer_cluster_py_ndarray_2781105897590886682_0\n", "\n", "\n", "cluster_py_ndarray_2781105897590886682_0\n", "\n", "\n", "\n", "outer_cluster_py_value_5338970148915291456_0\n", "\n", "\n", "cluster_py_value_5338970148915291456_0\n", "\n", "\n", "\n", "outer_cluster_Values.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Values.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_Value.__init___0_0\n", "\n", "\n", "cluster_Value.__init___0_0\n", "\n", "\n", "\n", "\n", "Values.__init___5871781006564002453_0:s->NDArray.__getitem___13531250035159840349\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___5871781006564002453:s->Values.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "cross_6828067974578293639:s->py_ndarray_12463696466920899969\n", "\n", "\n", "\n", "\n", "\n", "cross_6828067974578293639:s->arange_16783941965674463102\n", "\n", "\n", "\n", "\n", "\n", "py_ndarray_2781105897590886682:s->py_ndarray_2781105897590886682_0\n", "\n", "\n", "\n", "\n", "\n", "py_ndarray_12463696466920899969:s->py_ndarray_12463696466920899969_0\n", "\n", "\n", "\n", "\n", "\n", "arange_16783941965674463102:s->py_value_8004441328793213481\n", "\n", "\n", "\n", "\n", "\n", "py_value_5338970148915291456:s->py_value_5338970148915291456_0\n", "\n", "\n", "\n", "\n", "\n", "NDArray.__getitem___1081172882011038115:s->Values.__init___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "NDArray.__getitem___1081172882011038115:s->py_ndarray_2781105897590886682\n", "\n", "\n", "\n", "\n", "\n", "Value.__mul___14883133402278733943:s->Values.__getitem___17106626079223511235\n", "\n", "\n", "\n", "\n", "\n", "Value.__mul___14883133402278733943:s->NDArray.__getitem___13531250035159840349\n", "\n", "\n", "\n", "\n", "\n", "Values.__getitem___17106626079223511235:s->Values.__init___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Values.__getitem___17106626079223511235:s->Value.__init___0\n", "\n", "\n", "\n", "\n", "\n", "py_value_8004441328793213481:s->py_value_8004441328793213481_0\n", "\n", "\n", "\n", "\n", "\n", "NDArray.__getitem___13531250035159840349:s->Values.__init___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "NDArray.__getitem___13531250035159840349:s->arange_16783941965674463102\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___0:s->Value.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "py_ndarray_12463696466920899969_0\n", "\n", ""np.arange(x)"\n", "\n", "\n", "\n", "\n", "py_value_8004441328793213481_0\n", "\n", ""x"\n", "\n", "\n", "\n", "\n", "py_ndarray_2781105897590886682_0\n", "\n", ""np.multiply.outer(np.arange(x), np.arange(x))"\n", "\n", "\n", "\n", "\n", "py_value_5338970148915291456_0\n", "\n", ""x * x"\n", "\n", "\n", "\n", "\n", "Value.__init___0_0\n", "\n", "0\n", "\n", "\n", "\n", "\n", "Values.__init___5871781006564002453_0\n", "\n", "Vec[Value]\n", "\n", "\n", "\n", "\n", "Values.__init___5871781006564002453\n", "\n", "Values.__init__\n", "\n", "\n", "\n", "\n", "cross_6828067974578293639\n", "\n", "cross\n", "\n", "\n", "\n", "\n", "py_ndarray_2781105897590886682\n", "\n", "py_ndarray\n", "\n", "\n", "\n", "\n", "py_ndarray_12463696466920899969\n", "\n", "py_ndarray\n", "\n", "\n", "\n", "\n", "arange_16783941965674463102\n", "\n", "arange\n", "\n", "\n", "\n", "\n", "py_value_5338970148915291456\n", "\n", "py_value\n", "\n", "\n", "\n", "\n", "NDArray.__getitem___1081172882011038115\n", "\n", "NDArray.__getitem__\n", "\n", "\n", "\n", "\n", "Value.__mul___14883133402278733943\n", "\n", "Value.__mul__\n", "\n", "\n", "\n", "\n", "Values.__getitem___17106626079223511235\n", "\n", "Values.__getitem__\n", "\n", "\n", "\n", "\n", "py_value_8004441328793213481\n", "\n", "py_value\n", "\n", "\n", "\n", "\n", "NDArray.__getitem___13531250035159840349\n", "\n", "NDArray.__getitem__\n", "\n", "\n", "\n", "\n", "Value.__init___0\n", "\n", "Value.__init__\n", "\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from IPython.display import SVG, display\n", "\n", "with open(\"big_graph.svg\") as f:\n", " display(SVG(f.read()))" ] }, { "cell_type": "markdown", "id": "d4ef7a6c-5fca-46ff-89d6-ab7e659f1c82", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "source": [ "_Saul Shanabrook - July 20, 2023_\n" ] }, { "cell_type": "markdown", "id": "72e644b5-c987-45de-87d7-ee9da885b85f", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Open Source Data Science Ecosystem in Python\n", "\n", "> The term \u201cecosystem\u201d is often used to describe the modern open-source scientific software. In biology, the term \u201cecosystem\u201d is defined as a biological community of interacting organisms and their physical environment. Modern open-source scientific software development occurs in a similarly interconnected and interoperable fashion.\n", "\n", "from [Jupyter Meets the Earth: Ecosystem](https://jupytearth.org/jupyter-resources/introduction/ecosystem.html)\n", "\n", "![](https://jupytearth.org/_images/python-stack.png)\n" ] }, { "cell_type": "markdown", "id": "90785f75-e933-469f-b585-127f0e4fc584", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "### Aims\n", "\n", "- How can the tools we build foster greater **resiliancy, collaboration, and interdependence** in this ecosystem?
\n", "- How can they help it **stay flexible enough to adapt to the changing computational landscape** to empower users and authors?\n", "\n", "### What role could `egglog` play?\n", "\n", "- Bring the programming languages community closer to this space, providing theoretical frameworks for thinking about composition and language.\n", "- Constrained type system could support decentralized interopability and composition between data science libraries.\n" ] }, { "cell_type": "markdown", "id": "0b49d9a5-ef01-4f2b-a6f7-1bc1e5087201", "metadata": { "editable": true, "slideshow": { "slide_type": "skip" }, "tags": [] }, "source": [ "### Other Python EGraph Libraries\n", "\n", "- [`riswords/quiche`](https://github.com/riswords/quiche): Optimizing Python ASTs\n", "- [`egraphs-good/snake-egg`](https://github.com/egraphs-good/snake-egg): Generic bindings for `egg`, can bring any Python objects as expressions.\n", "- [EGraph library added to `ibis`](https://github.com/ibis-project/ibis/pull/5781): Conversions between dataframe syntax and SQL dialects\n" ] }, { "cell_type": "markdown", "id": "c4c37446-3426-4b57-a402-2a234b54d930", "metadata": { "editable": true, "slideshow": { "slide_type": "skip" }, "tags": [] }, "source": [ "TODO: Put this first, Say it's for library authors\n", "\n", "Semantics of python and egglog\n" ] }, { "cell_type": "markdown", "id": "eadf7129-68f3-4fcc-87a4-57e064f66fc8", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Started with `snake-egg`\n", "- Didn't want to re-invent the wheel, stay abreast of recent developments and research\n", "- Second piece that interests me\n", " - Unlike `egg` there are some builtin sorts, and can build user defined sorts on top of those\n", " - No host language conditions or data structures\n", " - Helps with optimization, more constrained\n", " - -> De-centers algorithms based on value, move to based on type. Everything becomes an interface.\n", " - Social dynamics, goal is ability to inovate and experiment, while still supporting existing use cases\n", " - New dataframe library comes out, supporting custom hardware. How dow we use it without rewriting code?\n", " - How do we have healthy ecosystem within these tools? Power\n", " - If it's too hard, encourages centralized monopolistic actors to step in provide one stop shop solutions for users.\n", " - Active problem in the community, with things like trying to standardize on interop.\n", " - Before getting too abstract, let's go to an example\n" ] }, { "cell_type": "markdown", "id": "ba2b7093-0927-45ff-99ca-d58c31c9f5c6", "metadata": { "editable": true, "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "skip" }, "tags": [] }, "source": [ "## What is an e-graph?\n" ] }, { "cell_type": "markdown", "id": "319f9e5c-7165-4844-b957-a77ce807f98d", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "> E-graphs are these super wonderful data structures for managing equality and equivalence information. They are traditionally used inside of constraint solvers and automated theorem provers to implement **congruence closure**, an efficient algorithm for equational reasoning---but they can also be used to implement **rewrite systems**.\n", ">\n", "> [Talia Ringer - \"Proof Automation\" course](https://dependenttyp.es/classes/readings/17-egraphs.html)\n" ] }, { "cell_type": "markdown", "id": "34ac3ee6-4053-49d7-b9ee-0adafd3dabb6", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Come from automated theorum proving world\n", "- Something congruence, which is like how triangles are similar but not equal,\n", "- Can be used for term rewriting\n" ] }, { "cell_type": "markdown", "id": "d4a57fd4-1253-47fb-82f2-476c80fdddab", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "source": [ "> In abstract algebra, a congruence relation (or simply congruence) is an equivalence relation on an algebraic structure (such as a group, ring, or vector space) that is compatible with the structure in the sense that **algebraic operations done with equivalent elements will yield equivalent elements**.\n", ">\n", "> [Wikipedia - Congruence relation](https://en.wikipedia.org/wiki/Congruence_relation)\n" ] }, { "cell_type": "markdown", "id": "fa5cbdaa-d89e-4602-ab36-ce0608ce3cc7", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- doing one thing on a set will be the same as doing it on another\n" ] }, { "cell_type": "markdown", "id": "89509032-cc46-4489-8532-d60f9b455db7", "metadata": { "editable": true, "slideshow": { "slide_type": "skip" }, "tags": [] }, "source": [ "### Congruence Closure\n" ] }, { "cell_type": "code", "execution_count": null, "id": "bb6baad4", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 2, "id": "5d4831fb-6c07-454b-9767-e1aeb452eeb2", "metadata": { "editable": true, "slideshow": { "slide_type": "skip" }, "tags": [] }, "outputs": [], "source": [ "from __future__ import annotations" ] }, { "cell_type": "code", "execution_count": 3, "id": "51ab67c6-c099-4a66-9344-3c4884ac33bf", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453:s->b_0\n", "\n", "\n", "\n", "\n", "\n", "operation_17615343019692007359:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "operation_17615343019692007359:s->c_0\n", "\n", "\n", "\n", "\n", "\n", "a_0\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "\n", "\n", "b_0\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "\n", "\n", "c_0\n", "\n", "\n", "c\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_b_0\n", "\n", "\n", "a_b\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_17615343019692007359\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_c_0\n", "\n", "\n", "a_c\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453:s->b_0\n", "\n", "\n", "\n", "\n", "\n", "operation_17615343019692007359:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "operation_17615343019692007359:s->c_0\n", "\n", "\n", "\n", "\n", "\n", "a_0\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "\n", "\n", "b_0\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "\n", "\n", "c_0\n", "\n", "\n", "c\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_b_0\n", "\n", "\n", "a_b\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_17615343019692007359\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_c_0\n", "\n", "\n", "a_c\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={'operation': FunctionDecl(arg_types=(TypeRefWithVars(name='Structure', args=()), TypeRefWithVars(name='Structure', args=())), arg_names=('l', 'r'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Structure', args=()), var_arg_type=None)}, _classes={'Structure': ClassDecl(methods={}, class_methods={}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={'a': JustTypeRef(name='Structure', args=()), 'b': JustTypeRef(name='Structure', args=()), 'c': JustTypeRef(name='Structure', args=())}, _egg_fn_to_callable_refs=defaultdict(, {'!=': {MethodRef(class_name='Structure', method_name='__ne__')}, 'a': {ConstantRef(name='a')}, 'b': {ConstantRef(name='b')}, 'c': {ConstantRef(name='c')}, 'operation': {FunctionRef(name='operation')}}), _callable_ref_to_egg_fn={MethodRef(class_name='Structure', method_name='__ne__'): '!=', ConstantRef(name='a'): 'a', ConstantRef(name='b'): 'b', ConstantRef(name='c'): 'c', FunctionRef(name='operation'): 'operation'}, _egg_sort_to_type_ref={'Structure': JustTypeRef(name='Structure', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Structure', args=()): 'Structure'})))" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from egglog import *\n", "\n", "egraph = EGraph()\n", "\n", "\n", "class Structure(Expr): ...\n", "\n", "\n", "a = egraph.constant(\"a\", Structure)\n", "b = egraph.constant(\"b\", Structure)\n", "c = egraph.constant(\"c\", Structure)\n", "\n", "\n", "@function\n", "def operation(l: Structure, r: Structure) -> Structure: ...\n", "\n", "\n", "a_b = egraph.let(\"a_b\", operation(a, b))\n", "a_c = egraph.let(\"a_c\", operation(a, c))\n", "\n", "egraph" ] }, { "cell_type": "markdown", "id": "9ffbef64-c611-4796-a085-09e63aab3b02", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Define a structure, define an operation on that structure\n", "- Define two elements\n", "- Are they equal?\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "80129d3e-c785-407e-a761-f9b767027f7a", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "ename": "EggSmolError", "evalue": "Check failed: \n(= a_b a_c)", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mEggSmolError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[4], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43megraph\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcheck\u001b[49m\u001b[43m(\u001b[49m\u001b[43meq\u001b[49m\u001b[43m(\u001b[49m\u001b[43ma_b\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto\u001b[49m\u001b[43m(\u001b[49m\u001b[43ma_c\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/egraph.py:721\u001b[0m, in \u001b[0;36mEGraph.check\u001b[0;34m(self, *facts)\u001b[0m\n\u001b[1;32m 717\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcheck\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39mfacts: FactLike) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 718\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 719\u001b[0m \u001b[38;5;124;03m Check if a fact is true in the egraph.\u001b[39;00m\n\u001b[1;32m 720\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 721\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_process_commands\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_facts_to_check\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfacts\u001b[49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/egraph.py:634\u001b[0m, in \u001b[0;36mEGraph._process_commands\u001b[0;34m(self, commands)\u001b[0m\n\u001b[1;32m 633\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_process_commands\u001b[39m(\u001b[38;5;28mself\u001b[39m, commands: Iterable[bindings\u001b[38;5;241m.\u001b[39m_Command]) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 634\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_egraph\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_program\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mcommands\u001b[49m\u001b[43m)\u001b[49m\n", "\u001b[0;31mEggSmolError\u001b[0m: Check failed: \n(= a_b a_c)" ] } ], "source": [ "egraph.check(eq(a_b).to(a_c))" ] }, { "cell_type": "code", "execution_count": 5, "id": "e7b23122-0659-4cb2-b8cc-68bb7e71575a", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453:s->b_0\n", "\n", "\n", "\n", "\n", "\n", "a_0\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_b_0\n", "\n", "\n", "a_b\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_c_0\n", "\n", "\n", "a_c\n", "\n", "\n", "\n", "\n", "\n", "\n", "c_0\n", "\n", "\n", "c\n", "\n", "\n", "\n", "\n", "\n", "\n", "b_0\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453:s->b_0\n", "\n", "\n", "\n", "\n", "\n", "a_0\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_b_0\n", "\n", "\n", "a_b\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_c_0\n", "\n", "\n", "a_c\n", "\n", "\n", "\n", "\n", "\n", "\n", "c_0\n", "\n", "\n", "c\n", "\n", "\n", "\n", "\n", "\n", "\n", "b_0\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={'operation': FunctionDecl(arg_types=(TypeRefWithVars(name='Structure', args=()), TypeRefWithVars(name='Structure', args=())), arg_names=('l', 'r'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Structure', args=()), var_arg_type=None)}, _classes={'Structure': ClassDecl(methods={}, class_methods={}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={'a': JustTypeRef(name='Structure', args=()), 'b': JustTypeRef(name='Structure', args=()), 'c': JustTypeRef(name='Structure', args=())}, _egg_fn_to_callable_refs=defaultdict(, {'!=': {MethodRef(class_name='Structure', method_name='__ne__')}, 'a': {ConstantRef(name='a')}, 'b': {ConstantRef(name='b')}, 'c': {ConstantRef(name='c')}, 'operation': {FunctionRef(name='operation')}}), _callable_ref_to_egg_fn={MethodRef(class_name='Structure', method_name='__ne__'): '!=', ConstantRef(name='a'): 'a', ConstantRef(name='b'): 'b', ConstantRef(name='c'): 'c', FunctionRef(name='operation'): 'operation'}, _egg_sort_to_type_ref={'Structure': JustTypeRef(name='Structure', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Structure', args=()): 'Structure'})))" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph.register(union(b).with_(c))\n", "egraph.run(1)\n", "egraph.check(eq(a_b).to(a_c))\n", "egraph" ] }, { "cell_type": "markdown", "id": "09365349-391d-46d8-b6aa-eb09d1e91626", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "source": [ "We just used `egglog` to\n", "\n", "- Define a structure\n", "- Define some operation on that structure\n", "- See it give us a congruence relation on that structure\n", " - \"algebraic operations done with equivalent elements will yield equivalent elements\"\n", " - We call a set of equivalent elements an **\"e-class\"** i.e. {a} or {b, c}\n", " - We only store pointers to other e-classes, not elements\n" ] }, { "cell_type": "markdown", "id": "69ebee03-5dd6-4985-83ee-fbabbf3c2a91", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Combining elements... so that operations done on two elements of the same\n" ] }, { "cell_type": "markdown", "id": "f2ddca09-d7bd-44be-807f-dba33a154ef8", "metadata": { "editable": true, "slideshow": { "slide_type": "skip" }, "tags": [] }, "source": [ "### \"Rewrite systems\"?\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "0244d1bb-3925-431e-9afc-18e9df655e81", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453:s->b_0\n", "\n", "\n", "\n", "\n", "\n", "operation_956286968014291186:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "operation_956286968014291186:s->c_0\n", "\n", "\n", "\n", "\n", "\n", "a_0\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_956286968014291186\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_b_0\n", "\n", "\n", "a_b\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_c_0\n", "\n", "\n", "a_c\n", "\n", "\n", "\n", "\n", "\n", "\n", "c_0\n", "\n", "\n", "c\n", "\n", "\n", "\n", "\n", "\n", "\n", "b_0\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453:s->b_0\n", "\n", "\n", "\n", "\n", "\n", "operation_956286968014291186:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "operation_956286968014291186:s->c_0\n", "\n", "\n", "\n", "\n", "\n", "a_0\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_5871781006564002453\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_956286968014291186\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_b_0\n", "\n", "\n", "a_b\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_c_0\n", "\n", "\n", "a_c\n", "\n", "\n", "\n", "\n", "\n", "\n", "c_0\n", "\n", "\n", "c\n", "\n", "\n", "\n", "\n", "\n", "\n", "b_0\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={'operation': FunctionDecl(arg_types=(TypeRefWithVars(name='Structure', args=()), TypeRefWithVars(name='Structure', args=())), arg_names=('l', 'r'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Structure', args=()), var_arg_type=None)}, _classes={'Structure': ClassDecl(methods={}, class_methods={}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={'a': JustTypeRef(name='Structure', args=()), 'b': JustTypeRef(name='Structure', args=()), 'c': JustTypeRef(name='Structure', args=())}, _egg_fn_to_callable_refs=defaultdict(, {'!=': {MethodRef(class_name='Structure', method_name='__ne__')}, 'a': {ConstantRef(name='a')}, 'b': {ConstantRef(name='b')}, 'c': {ConstantRef(name='c')}, 'operation': {FunctionRef(name='operation')}}), _callable_ref_to_egg_fn={MethodRef(class_name='Structure', method_name='__ne__'): '!=', ConstantRef(name='a'): 'a', ConstantRef(name='b'): 'b', ConstantRef(name='c'): 'c', FunctionRef(name='operation'): 'operation'}, _egg_sort_to_type_ref={'Structure': JustTypeRef(name='Structure', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Structure', args=()): 'Structure'})))" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@egraph.register\n", "def _operation_commutative(left: Structure, right: Structure):\n", " yield rewrite(operation(left, right)).to(operation(right, left))\n", "\n", "\n", "egraph.run(run().saturate())\n", "egraph.check(eq(operation(a, b)).to(operation(b, a)))\n", "egraph" ] }, { "cell_type": "markdown", "id": "b0cb9d48-f0c5-4e19-b74d-a199a229f586", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "source": [ "`egglog` can also be used for rewrite system:\n", "\n", "- Define rules which will be matched on the e-graph\n", "- The results will be added to the e-graph\n", "- Can keep runnning these rules until the e-graph is \"saturated\"\n" ] }, { "cell_type": "code", "execution_count": 7, "id": "ff761614-48c3-4fb0-b07a-3a87eada032a", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "data": { "text/plain": [ "b" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@egraph.register\n", "def _operation_identity(s: Structure):\n", " yield rewrite(operation(c, s)).to(c)\n", "\n", "\n", "egraph.run(run().saturate())\n", "egraph.extract(operation(c, a))" ] }, { "cell_type": "code", "execution_count": 8, "id": "e6cf516e-9994-4edc-bd35-9143d2cb1817", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [ "remove-input" ] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "\n", "operation_1912573936028582372:s->c_0\n", "\n", "\n", "\n", "\n", "\n", "operation_1912573936028582372:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "operation_11743562013128004906:s->a_b_0\n", "\n", "\n", "\n", "\n", "\n", "operation_11743562013128004906:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "a_c_0\n", "\n", "\n", "a_c\n", "\n", "\n", "\n", "\n", "\n", "\n", "b_0\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_1912573936028582372\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_11743562013128004906\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_b_0\n", "\n", "\n", "a_b\n", "\n", "\n", "\n", "\n", "\n", "\n", "c_0\n", "\n", "\n", "c\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_0\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "\n", "operation_1912573936028582372:s->c_0\n", "\n", "\n", "\n", "\n", "\n", "operation_1912573936028582372:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "operation_11743562013128004906:s->a_b_0\n", "\n", "\n", "\n", "\n", "\n", "operation_11743562013128004906:s->a_0\n", "\n", "\n", "\n", "\n", "\n", "a_c_0\n", "\n", "\n", "a_c\n", "\n", "\n", "\n", "\n", "\n", "\n", "b_0\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_1912573936028582372\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "operation_11743562013128004906\n", "\n", "\n", "operation\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_b_0\n", "\n", "\n", "a_b\n", "\n", "\n", "\n", "\n", "\n", "\n", "c_0\n", "\n", "\n", "c\n", "\n", "\n", "\n", "\n", "\n", "\n", "a_0\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={'operation': FunctionDecl(arg_types=(TypeRefWithVars(name='Structure', args=()), TypeRefWithVars(name='Structure', args=())), arg_names=('l', 'r'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Structure', args=()), var_arg_type=None)}, _classes={'Structure': ClassDecl(methods={}, class_methods={}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={'a': JustTypeRef(name='Structure', args=()), 'b': JustTypeRef(name='Structure', args=()), 'c': JustTypeRef(name='Structure', args=())}, _egg_fn_to_callable_refs=defaultdict(, {'!=': {MethodRef(class_name='Structure', method_name='__ne__')}, 'a': {ConstantRef(name='a')}, 'b': {ConstantRef(name='b')}, 'c': {ConstantRef(name='c')}, 'operation': {FunctionRef(name='operation')}}), _callable_ref_to_egg_fn={MethodRef(class_name='Structure', method_name='__ne__'): '!=', ConstantRef(name='a'): 'a', ConstantRef(name='b'): 'b', ConstantRef(name='c'): 'c', FunctionRef(name='operation'): 'operation'}, _egg_sort_to_type_ref={'Structure': JustTypeRef(name='Structure', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Structure', args=()): 'Structure'})))" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph" ] }, { "cell_type": "markdown", "id": "c2b26c2c-c82b-49aa-9957-09b415af24e6", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "source": [ "- Define `c` as the identity for this operation\n", "- \"extract\" an expression to find lowest cost equivalent expression\n" ] }, { "cell_type": "markdown", "id": "4867f83d-c51c-4860-8c4d-65094404f503", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "What are e-graphs?\n", "\n", "- Data structure to hold \"congruence closure\" i.e. sets of equivalent items\n", "- Can implement term rewriting system on them\n", " - Order of rewrites don't matter b/c application only add information\n", " - Extract \"best\" expression from e-graph after applying rules\n" ] }, { "cell_type": "markdown", "id": "0d6a04c7-4cc5-4375-b95c-038960ed231e", "metadata": { "editable": true, "slideshow": { "slide_type": "skip" }, "tags": [] }, "source": [ "## What is `egglog`?\n" ] }, { "cell_type": "markdown", "id": "03527e0e-448e-4b57-8532-02a945e7f1d0", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "![](egg.png)\n" ] }, { "cell_type": "markdown", "id": "54f61359-111b-45f8-b7b2-e54d21aa2ccd", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Will show how some examples translate\n" ] }, { "cell_type": "markdown", "id": "673a0c32-2b21-431e-b5fc-6d8b29abf6a5", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "### Sorts, expressions, and functions\n" ] }, { "cell_type": "code", "execution_count": 9, "id": "33d34134-78c9-472b-b364-479c3aca3b23", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Var_7848520443469635519_0\n", "\n", "\n", "cluster_Var_7848520443469635519_0\n", "\n", "\n", "\n", "outer_cluster_Num_17615343019692007359_0\n", "\n", "\n", "cluster_Num_17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_Num_16783941965674463102_0\n", "\n", "\n", "cluster_Num_16783941965674463102_0\n", "\n", "\n", "\n", "outer_cluster_Num_11743562013128004906_0\n", "\n", "\n", "cluster_Num_11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "outer_cluster_6\n", "\n", "\n", "cluster_6\n", "\n", "\n", "\n", "outer_cluster_7\n", "\n", "\n", "cluster_7\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_5\n", "\n", "\n", "cluster_5\n", "\n", "\n", "\n", "\n", "Add_7659469028595837896:s->Var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Add_7659469028595837896:s->Num_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Mul_5871781006564002453:s->Num_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Mul_5871781006564002453:s->Var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Add_13095445380246898500:s->Mul_5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Add_13095445380246898500:s->Num_16783941965674463102\n", "\n", "\n", "\n", "\n", "\n", "Num_11743562013128004906:s->Num_11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "Var_7848520443469635519:s->Var_7848520443469635519_0\n", "\n", "\n", "\n", "\n", "\n", "Mul_17615343019692007359:s->Add_7659469028595837896\n", "\n", "\n", "\n", "\n", "\n", "Mul_17615343019692007359:s->Num_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num_17615343019692007359:s->Num_17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "Num_16783941965674463102:s->Num_16783941965674463102_0\n", "\n", "\n", "\n", "\n", "\n", "Var_7848520443469635519_0\n", "\n", "\n", ""x"\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num_17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num_16783941965674463102_0\n", "\n", "\n", "6\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num_11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Add_7659469028595837896\n", "\n", "\n", "Add\n", "\n", "\n", "\n", "\n", "\n", "\n", "Mul_5871781006564002453\n", "\n", "\n", "Mul\n", "\n", "\n", "\n", "\n", "\n", "\n", "Add_13095445380246898500\n", "\n", "\n", "Add\n", "\n", "\n", "\n", "\n", "\n", "\n", "expr2_0\n", "\n", "\n", "expr2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num_11743562013128004906\n", "\n", "\n", "Num\n", "\n", "\n", "\n", "\n", "\n", "\n", "Var_7848520443469635519\n", "\n", "\n", "Var\n", "\n", "\n", "\n", "\n", "\n", "\n", "expr1_0\n", "\n", "\n", "expr1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Mul_17615343019692007359\n", "\n", "\n", "Mul\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num_17615343019692007359\n", "\n", "\n", "Num\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num_16783941965674463102\n", "\n", "\n", "Num\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%egglog graph\n", "(datatype Math\n", " (Num i64)\n", " (Var String)\n", " (Add Math Math)\n", " (Mul Math Math))\n", "\n", "(define expr1 (Mul (Num 2) (Add (Var \"x\") (Num 3))))\n", "(define expr2 (Add (Num 6) (Mul (Num 2) (Var \"x\"))))\n" ] }, { "cell_type": "markdown", "id": "1c0f4ee3-f5bd-49e7-b2a6-81088809eb08", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- User defined sorts\n", "- Expressions\n", " - expr1 and expr2 in their own e-classes, we haven't ran any rules\n", "- `%%egglog` magic, Writing egglog in Notebook, graphs, output inline.\n" ] }, { "cell_type": "code", "execution_count": 10, "id": "4c774ee4-722c-4a3a-b61b-37733b435948", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Num.__init___17615343019692007359_0\n", "\n", "\n", "cluster_Num.__init___17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "outer_cluster_Num.__init___16783941965674463102_0\n", "\n", "\n", "cluster_Num.__init___16783941965674463102_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.var_7848520443469635519_0\n", "\n", "\n", "cluster_Num.var_7848520443469635519_0\n", "\n", "\n", "\n", "outer_cluster_6\n", "\n", "\n", "cluster_6\n", "\n", "\n", "\n", "outer_cluster_7\n", "\n", "\n", "cluster_7\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_5\n", "\n", "\n", "cluster_5\n", "\n", "\n", "\n", "\n", "Num.__add___7659469028595837896:s->Num.var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7659469028595837896:s->Num.__init___17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___5871781006564002453:s->Num.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___5871781006564002453:s->Num.var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___13095445380246898500:s->Num.__mul___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___13095445380246898500:s->Num.__init___16783941965674463102\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906:s->Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "Num.var_7848520443469635519:s->Num.var_7848520443469635519_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___17615343019692007359:s->Num.__add___7659469028595837896\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___17615343019692007359:s->Num.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359:s->Num.__init___17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___16783941965674463102:s->Num.__init___16783941965674463102_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___16783941965674463102_0\n", "\n", "\n", "6\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.var_7848520443469635519_0\n", "\n", "\n", ""x"\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7659469028595837896\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___5871781006564002453\n", "\n", "\n", "Num.__mul__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___13095445380246898500\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "expr2_0\n", "\n", "\n", "expr2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.var_7848520443469635519\n", "\n", "\n", "Num.var\n", "\n", "\n", "\n", "\n", "\n", "\n", "expr1_0\n", "\n", "\n", "expr1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___17615343019692007359\n", "\n", "\n", "Num.__mul__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___16783941965674463102\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Num.__init___17615343019692007359_0\n", "\n", "\n", "cluster_Num.__init___17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "outer_cluster_Num.__init___16783941965674463102_0\n", "\n", "\n", "cluster_Num.__init___16783941965674463102_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.var_7848520443469635519_0\n", "\n", "\n", "cluster_Num.var_7848520443469635519_0\n", "\n", "\n", "\n", "outer_cluster_6\n", "\n", "\n", "cluster_6\n", "\n", "\n", "\n", "outer_cluster_7\n", "\n", "\n", "cluster_7\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_5\n", "\n", "\n", "cluster_5\n", "\n", "\n", "\n", "\n", "Num.__add___7659469028595837896:s->Num.var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7659469028595837896:s->Num.__init___17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___5871781006564002453:s->Num.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___5871781006564002453:s->Num.var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___13095445380246898500:s->Num.__mul___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___13095445380246898500:s->Num.__init___16783941965674463102\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906:s->Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "Num.var_7848520443469635519:s->Num.var_7848520443469635519_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___17615343019692007359:s->Num.__add___7659469028595837896\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___17615343019692007359:s->Num.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359:s->Num.__init___17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___16783941965674463102:s->Num.__init___16783941965674463102_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___16783941965674463102_0\n", "\n", "\n", "6\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.var_7848520443469635519_0\n", "\n", "\n", ""x"\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7659469028595837896\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___5871781006564002453\n", "\n", "\n", "Num.__mul__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___13095445380246898500\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "expr2_0\n", "\n", "\n", "expr2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.var_7848520443469635519\n", "\n", "\n", "Num.var\n", "\n", "\n", "\n", "\n", "\n", "\n", "expr1_0\n", "\n", "\n", "expr1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___17615343019692007359\n", "\n", "\n", "Num.__mul__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___16783941965674463102\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={}, _classes={'Num': ClassDecl(methods={'__add__': FunctionDecl(arg_types=(TypeRefWithVars(name='Num', args=()), TypeRefWithVars(name='Num', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None), '__mul__': FunctionDecl(arg_types=(TypeRefWithVars(name='Num', args=()), TypeRefWithVars(name='Num', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_methods={'var': FunctionDecl(arg_types=(TypeRefWithVars(name='String', args=()),), arg_names=('name',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None), '__init__': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('value',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {'Num.var': {ClassMethodRef(class_name='Num', method_name='var')}, 'Num.__init__': {ClassMethodRef(class_name='Num', method_name='__init__')}, 'Num.__add__': {MethodRef(class_name='Num', method_name='__add__')}, 'Num.__mul__': {MethodRef(class_name='Num', method_name='__mul__')}, '!=': {MethodRef(class_name='Num', method_name='__ne__')}}), _callable_ref_to_egg_fn={ClassMethodRef(class_name='Num', method_name='var'): 'Num.var', ClassMethodRef(class_name='Num', method_name='__init__'): 'Num.__init__', MethodRef(class_name='Num', method_name='__add__'): 'Num.__add__', MethodRef(class_name='Num', method_name='__mul__'): 'Num.__mul__', MethodRef(class_name='Num', method_name='__ne__'): '!='}, _egg_sort_to_type_ref={'Num': JustTypeRef(name='Num', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Num', args=()): 'Num'})))" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph = EGraph()\n", "\n", "\n", "class Num(Expr):\n", " @classmethod\n", " def var(cls, name: StringLike) -> Num: ...\n", "\n", " def __init__(self, value: i64Like) -> None: ...\n", "\n", " def __add__(self, other: Num) -> Num: ...\n", "\n", " def __mul__(self, other: Num) -> Num: ...\n", "\n", "\n", "expr1 = egraph.let(\"expr1\", Num(2) * (Num.var(\"x\") + Num(3)))\n", "expr2 = egraph.let(\"expr2\", Num(6) + Num(2) * Num.var(\"x\"))\n", "egraph" ] }, { "cell_type": "markdown", "id": "1e32a7c4-fbb7-4dd2-8af1-c7fd22a3ca86", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Re-use existing Python class and functions\n", " - Humans and computers to understand the typing semantics\n", " - Humans read `__init__` and `__add__`.\n", " - Static type checkers. `Num(\"String\")` it won't work.\n", " - Static type checking drives much of the API design of the library\n", "- Operator overloading support infix operators\n", "- Names generated based on classes\n", " - Same operator on different types compile to different function with different signature\n" ] }, { "cell_type": "markdown", "id": "6efa3a03-cce0-4075-a767-84da0a7aec86", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "### Rewrite rules and checks\n" ] }, { "cell_type": "code", "execution_count": 11, "id": "99cb645c-f006-4e9e-bc39-762be3fa5d61", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Var_7848520443469635519_0\n", "\n", "\n", "cluster_Var_7848520443469635519_0\n", "\n", "\n", "\n", "outer_cluster_Num_17615343019692007359_0\n", "\n", "\n", "cluster_Num_17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_Num_16783941965674463102_0\n", "\n", "\n", "cluster_Num_16783941965674463102_0\n", "\n", "\n", "\n", "outer_cluster_Num_11743562013128004906_0\n", "\n", "\n", "cluster_Num_11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_6\n", "\n", "\n", "cluster_6\n", "\n", "\n", "\n", "outer_cluster_10\n", "\n", "\n", "cluster_10\n", "\n", "\n", "\n", "\n", "Num_17615343019692007359:s->Num_17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "Num_11743562013128004906:s->Num_11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "Var_7848520443469635519:s->Var_7848520443469635519_0\n", "\n", "\n", "\n", "\n", "\n", "Add_7659469028595837896:s->Num_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Add_7659469028595837896:s->Var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Add_7784354942592584825:s->Num_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Add_7784354942592584825:s->Var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Add_9842753449732275747:s->Mul_5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Add_9842753449732275747:s->Num_16783941965674463102\n", "\n", "\n", "\n", "\n", "\n", "Add_11849178328430774015:s->Mul_5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Add_11849178328430774015:s->Mul_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Mul_17615343019692007359:s->Num_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Mul_17615343019692007359:s->Add_7784354942592584825\n", "\n", "\n", "\n", "\n", "\n", "Mul_5871781006564002453:s->Num_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Mul_5871781006564002453:s->Var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Mul_11743562013128004906:s->Num_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Mul_11743562013128004906:s->Num_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num_16783941965674463102:s->Num_16783941965674463102_0\n", "\n", "\n", "\n", "\n", "\n", "Var_7848520443469635519_0\n", "\n", "\n", ""x"\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num_17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num_16783941965674463102_0\n", "\n", "\n", "6\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num_11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num_17615343019692007359\n", "\n", "\n", "Num\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num_11743562013128004906\n", "\n", "\n", "Num\n", "\n", "\n", "\n", "\n", "\n", "\n", "Var_7848520443469635519\n", "\n", "\n", "Var\n", "\n", "\n", "\n", "\n", "\n", "\n", "Add_7659469028595837896\n", "\n", "\n", "Add\n", "\n", "\n", "\n", "\n", "\n", "\n", "Add_7784354942592584825\n", "\n", "\n", "Add\n", "\n", "\n", "\n", "\n", "\n", "\n", "Add_9842753449732275747\n", "\n", "\n", "Add\n", "\n", "\n", "\n", "\n", "\n", "\n", "Add_11849178328430774015\n", "\n", "\n", "Add\n", "\n", "\n", "\n", "\n", "\n", "\n", "expr1_0\n", "\n", "\n", "expr1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Mul_17615343019692007359\n", "\n", "\n", "Mul\n", "\n", "\n", "\n", "\n", "\n", "\n", "expr2_0\n", "\n", "\n", "expr2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Mul_5871781006564002453\n", "\n", "\n", "Mul\n", "\n", "\n", "\n", "\n", "\n", "\n", "Mul_11743562013128004906\n", "\n", "\n", "Mul\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num_16783941965674463102\n", "\n", "\n", "Num\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%egglog graph continue\n", "(rewrite (Add a b)\n", " (Add b a))\n", "(rewrite (Mul a (Add b c))\n", " (Add (Mul a b) (Mul a c)))\n", "(rewrite (Add (Num a) (Num b))\n", " (Num (+ a b)))\n", "(rewrite (Mul (Num a) (Num b))\n", " (Num (* a b)))\n", "\n", "(run 10)\n", "(check (= expr1 expr2))\n" ] }, { "cell_type": "markdown", "id": "0f5ef7d7-e043-40ee-a334-2e9b34a7b33f", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- See equivalent, in same e-class now\n" ] }, { "cell_type": "code", "execution_count": 12, "id": "a7f568af-5655-4926-bb93-5c2415f267cb", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Num.__init___17615343019692007359_0\n", "\n", "\n", "cluster_Num.__init___17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_Num.__init___16783941965674463102_0\n", "\n", "\n", "cluster_Num.__init___16783941965674463102_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.var_7848520443469635519_0\n", "\n", "\n", "cluster_Num.var_7848520443469635519_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_6\n", "\n", "\n", "cluster_6\n", "\n", "\n", "\n", "outer_cluster_10\n", "\n", "\n", "cluster_10\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359:s->Num.__init___17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906:s->Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "Num.var_7848520443469635519:s->Num.var_7848520443469635519_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___17615343019692007359:s->Num.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___17615343019692007359:s->Num.__add___7784354942592584825\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___9842753449732275747:s->Num.__mul___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___9842753449732275747:s->Num.__init___16783941965674463102\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___11849178328430774015:s->Num.__mul___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___11849178328430774015:s->Num.__mul___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___5871781006564002453:s->Num.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___5871781006564002453:s->Num.var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___11743562013128004906:s->Num.__init___17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___11743562013128004906:s->Num.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___16783941965674463102:s->Num.__init___16783941965674463102_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7659469028595837896:s->Num.__init___17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7659469028595837896:s->Num.var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7784354942592584825:s->Num.__init___17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7784354942592584825:s->Num.var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___16783941965674463102_0\n", "\n", "\n", "6\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.var_7848520443469635519_0\n", "\n", "\n", ""x"\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.var_7848520443469635519\n", "\n", "\n", "Num.var\n", "\n", "\n", "\n", "\n", "\n", "\n", "expr1_0\n", "\n", "\n", "expr1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___17615343019692007359\n", "\n", "\n", "Num.__mul__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___9842753449732275747\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___11849178328430774015\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "expr2_0\n", "\n", "\n", "expr2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___5871781006564002453\n", "\n", "\n", "Num.__mul__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___11743562013128004906\n", "\n", "\n", "Num.__mul__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___16783941965674463102\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7659469028595837896\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7784354942592584825\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Num.__init___17615343019692007359_0\n", "\n", "\n", "cluster_Num.__init___17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_Num.__init___16783941965674463102_0\n", "\n", "\n", "cluster_Num.__init___16783941965674463102_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.var_7848520443469635519_0\n", "\n", "\n", "cluster_Num.var_7848520443469635519_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_6\n", "\n", "\n", "cluster_6\n", "\n", "\n", "\n", "outer_cluster_10\n", "\n", "\n", "cluster_10\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359:s->Num.__init___17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906:s->Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "Num.var_7848520443469635519:s->Num.var_7848520443469635519_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___17615343019692007359:s->Num.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___17615343019692007359:s->Num.__add___7784354942592584825\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___9842753449732275747:s->Num.__mul___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___9842753449732275747:s->Num.__init___16783941965674463102\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___11849178328430774015:s->Num.__mul___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___11849178328430774015:s->Num.__mul___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___5871781006564002453:s->Num.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___5871781006564002453:s->Num.var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___11743562013128004906:s->Num.__init___17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___11743562013128004906:s->Num.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___16783941965674463102:s->Num.__init___16783941965674463102_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7659469028595837896:s->Num.__init___17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7659469028595837896:s->Num.var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7784354942592584825:s->Num.__init___17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7784354942592584825:s->Num.var_7848520443469635519\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___16783941965674463102_0\n", "\n", "\n", "6\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.var_7848520443469635519_0\n", "\n", "\n", ""x"\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.var_7848520443469635519\n", "\n", "\n", "Num.var\n", "\n", "\n", "\n", "\n", "\n", "\n", "expr1_0\n", "\n", "\n", "expr1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___17615343019692007359\n", "\n", "\n", "Num.__mul__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___9842753449732275747\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___11849178328430774015\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "expr2_0\n", "\n", "\n", "expr2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___5871781006564002453\n", "\n", "\n", "Num.__mul__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__mul___11743562013128004906\n", "\n", "\n", "Num.__mul__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___16783941965674463102\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7659469028595837896\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___7784354942592584825\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={}, _classes={'Num': ClassDecl(methods={'__add__': FunctionDecl(arg_types=(TypeRefWithVars(name='Num', args=()), TypeRefWithVars(name='Num', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None), '__mul__': FunctionDecl(arg_types=(TypeRefWithVars(name='Num', args=()), TypeRefWithVars(name='Num', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_methods={'var': FunctionDecl(arg_types=(TypeRefWithVars(name='String', args=()),), arg_names=('name',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None), '__init__': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('value',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {'Num.var': {ClassMethodRef(class_name='Num', method_name='var')}, 'Num.__init__': {ClassMethodRef(class_name='Num', method_name='__init__')}, 'Num.__add__': {MethodRef(class_name='Num', method_name='__add__')}, 'Num.__mul__': {MethodRef(class_name='Num', method_name='__mul__')}, '!=': {MethodRef(class_name='Num', method_name='__ne__')}}), _callable_ref_to_egg_fn={ClassMethodRef(class_name='Num', method_name='var'): 'Num.var', ClassMethodRef(class_name='Num', method_name='__init__'): 'Num.__init__', MethodRef(class_name='Num', method_name='__add__'): 'Num.__add__', MethodRef(class_name='Num', method_name='__mul__'): 'Num.__mul__', MethodRef(class_name='Num', method_name='__ne__'): '!='}, _egg_sort_to_type_ref={'Num': JustTypeRef(name='Num', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Num', args=()): 'Num'})))" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@egraph.register\n", "def _(a: Num, b: Num, c: Num, i: i64, j: i64):\n", " yield rewrite(a + b).to(b + a)\n", " yield rewrite(a * (b + c)).to((a * b) + (a * c))\n", " yield rewrite(Num(i) + Num(j)).to(Num(i + j))\n", " yield rewrite(Num(i) * Num(j)).to(Num(i * j))\n", "\n", "\n", "egraph.run(10)\n", "egraph.check(eq(expr1).to(expr2))\n", "egraph" ] }, { "cell_type": "markdown", "id": "208b3db5-e2d7-48f8-afaf-e637c132691e", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Similar in Python, rewrite rules, run, check\n", "- Notice that all vars need types, unlike inferred in egglog\n", " - Both for static type checkers to verify\n", " - And for runtime to know what methods\n" ] }, { "cell_type": "markdown", "id": "cd095e65-074d-44d1-b180-060aa34a92d7", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "### Extracting lowest cost expression\n" ] }, { "cell_type": "code", "execution_count": 13, "id": "33644682-1e44-4d30-9ed8-9126ff00582b", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Extracted with cost 8: (Mul (Num 2) (Add (Var \"x\") (Num 3)))\n" ] } ], "source": [ "%%egglog continue output\n", "(extract expr1)\n" ] }, { "cell_type": "markdown", "id": "b8932052-014c-4e93-b3f3-b8e112b77811", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Extract lowest cost expr\n" ] }, { "cell_type": "code", "execution_count": 14, "id": "63308ba8-f31a-4809-bf4a-c6816cbcdc00", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [ { "data": { "text/plain": [ "(Num(2) * Num.var(\"x\")) + Num(6)" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph.extract(expr1)" ] }, { "cell_type": "markdown", "id": "386bb340-06a1-4c86-88ba-33201d4214ca", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- get back expr object\n", "- Str representation is Python syntax\n" ] }, { "cell_type": "markdown", "id": "f5e0d729-028a-4af4-947f-62a2e109d28a", "metadata": { "editable": true, "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "### Multipart Rules\n" ] }, { "cell_type": "code", "execution_count": 15, "id": "0bea7d72-bf5c-47c4-95ac-e2926ad33cf3", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_fib_16783941965674463102\n", "\n", "\n", "cluster_fib_16783941965674463102\n", "\n", "\n", "\n", "outer_cluster_fib_11743562013128004906_0\n", "\n", "\n", "cluster_fib_11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_fib_16783941965674463102_0\n", "\n", "\n", "cluster_fib_16783941965674463102_0\n", "\n", "\n", "\n", "outer_cluster_fib_11743562013128004906\n", "\n", "\n", "cluster_fib_11743562013128004906\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196\n", "\n", "\n", "cluster_fib_5040379952546458196\n", "\n", "\n", "\n", "outer_cluster_fib_10080759905092916392_0\n", "\n", "\n", "cluster_fib_10080759905092916392_0\n", "\n", "\n", "\n", "outer_cluster_fib_17615343019692007359_0\n", "\n", "\n", "cluster_fib_17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_fib_17615343019692007359\n", "\n", "\n", "cluster_fib_17615343019692007359\n", "\n", "\n", "\n", "outer_cluster_fib_0\n", "\n", "\n", "cluster_fib_0\n", "\n", "\n", "\n", "outer_cluster_fib_10912160959110460649_0\n", "\n", "\n", "cluster_fib_10912160959110460649_0\n", "\n", "\n", "\n", "outer_cluster_fib_4208978898528913939\n", "\n", "\n", "cluster_fib_4208978898528913939\n", "\n", "\n", "\n", "outer_cluster_fib_10080759905092916392\n", "\n", "\n", "cluster_fib_10080759905092916392\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196_0\n", "\n", "\n", "cluster_fib_5040379952546458196_0\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453\n", "\n", "\n", "cluster_fib_5871781006564002453\n", "\n", "\n", "\n", "outer_cluster_fib_4208978898528913939_0\n", "\n", "\n", "cluster_fib_4208978898528913939_0\n", "\n", "\n", "\n", "outer_cluster_fib_10912160959110460649\n", "\n", "\n", "cluster_fib_10912160959110460649\n", "\n", "\n", "\n", "\n", "fib_16783941965674463102:s->fib_16783941965674463102_0\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906:s->fib_11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196:s->fib_5040379952546458196_0\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359:s->fib_17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_4208978898528913939:s->fib_4208978898528913939_0\n", "\n", "\n", "\n", "\n", "\n", "fib_10080759905092916392:s->fib_10080759905092916392_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_10912160959110460649:s->fib_10912160959110460649_0\n", "\n", "\n", "\n", "\n", "\n", "fib_16783941965674463102\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_16783941965674463102_value\n", "\n", "\n", "8\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_16783941965674463102_0\n", "\n", "\n", "6\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906_value\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_value\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_10080759905092916392_0\n", "\n", "\n", "8\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359_value\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_value\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_10912160959110460649_0\n", "\n", "\n", "5\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_4208978898528913939\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_4208978898528913939_value\n", "\n", "\n", "13\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_10080759905092916392\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_10080759905092916392_value\n", "\n", "\n", "21\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_0\n", "\n", "\n", "4\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_value\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_4208978898528913939_0\n", "\n", "\n", "7\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_10912160959110460649\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_10912160959110460649_value\n", "\n", "\n", "5\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%egglog graph\n", "(function fib (i64) i64)\n", "\n", "(set (fib 0) 0)\n", "(set (fib 1) 1)\n", "(rule ((= f0 (fib x))\n", " (= f1 (fib (+ x 1))))\n", " ((set (fib (+ x 2)) (+ f0 f1))))\n", "\n", "(run 7)\n", "(check (= (fib 7) 13))\n" ] }, { "cell_type": "markdown", "id": "2dc964ef-f5ee-4b7c-80a5-5a11b848ece7", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Rule that depend on facts and execute actions\n" ] }, { "cell_type": "code", "execution_count": 16, "id": "7f4bd927-ccd6-4240-aec0-123d93a782c5", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [], "source": [ "fib_egraph = EGraph()\n", "\n", "\n", "@fib_egraph.function\n", "def fib(x: i64Like) -> i64: ...\n", "\n", "\n", "@fib_egraph.register\n", "def _(f0: i64, f1: i64, x: i64):\n", " yield set_(fib(0)).to(i64(1))\n", " yield set_(fib(1)).to(i64(1))\n", " yield rule(\n", " eq(f0).to(fib(x)),\n", " eq(f1).to(fib(x + 1)),\n", " ).then(set_(fib(x + 2)).to(f0 + f1))\n", "\n", "\n", "fib_egraph.run(7)\n", "fib_egraph.check(eq(fib(7)).to(i64(21)))" ] }, { "cell_type": "markdown", "id": "df10f994-3e91-4663-807a-877f3dd50e04", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- `set_` and and `eq` both type safe. Required builder syntax\n" ] }, { "cell_type": "markdown", "id": "5b4d8cba-3e99-4e61-afe0-c18724c0d358", "metadata": { "editable": true, "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "### Include & Modules\n" ] }, { "cell_type": "code", "execution_count": 17, "id": "68179969-f9e0-43ef-851f-bd2295bd5a21", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Overwriting path.egg\n" ] } ], "source": [ "%%writefile path.egg\n", "(relation path (i64 i64))\n", "(relation edge (i64 i64))\n", "\n", "(rule ((edge x y))\n", " ((path x y)))\n", "\n", "(rule ((path x y) (edge y z))\n", " ((path x z)))\n" ] }, { "cell_type": "code", "execution_count": 18, "id": "39273d7a-926c-4022-8514-8f5b297cfdfb", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ "%%egglog\n", "(include \"path.egg\")\n", "(edge 1 2)\n", "(edge 2 3)\n", "(edge 3 4)\n", "(run 3)\n", "(check (path 1 3))\n" ] }, { "cell_type": "markdown", "id": "ac6aec27-654d-4cf5-bb4e-3341074ffa64", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Include another file for re-useability\n" ] }, { "cell_type": "code", "execution_count": 19, "id": "ad42a38e-ad5d-476b-8ecb-a04a56a618d1", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [], "source": [ "mod = Module()\n", "path = mod.relation(\"path\", i64, i64)\n", "edge = mod.relation(\"edge\", i64, i64)\n", "\n", "\n", "@mod.register\n", "def _(x: i64, y: i64, z: i64):\n", " yield rule(edge(x, y)).then(path(x, y))\n", " yield rule(path(x, y), edge(y, z)).then(path(x, z))" ] }, { "cell_type": "markdown", "id": "93b04224-cf27-41aa-b3e8-4fb5f5bb1508", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Modules same in Python\n", "- Supports defining rules, etc, but doesn't actually run them, just builds up commands\n" ] }, { "cell_type": "code", "execution_count": 20, "id": "8f8932a2-f6ea-4a7c-a4f3-41e4455aa33e", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ "egraph = EGraph([mod])\n", "egraph.register(edge(1, 2), edge(2, 3), edge(3, 4))\n", "egraph.run(3)\n", "egraph.check(path(1, 3))" ] }, { "cell_type": "markdown", "id": "99f0f9f2-297d-45ac-bc84-053f591d894d", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Then when we depend on them, it will run those commands first.\n", "- Allows distribution of code and others to re-use it, using existing Python import mechanisms.\n" ] }, { "cell_type": "markdown", "id": "08d88a72-6271-41eb-91f4-978d86b4f5ff", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "### Python Objects\n", "\n", "`egglog` supports `i64`, `f64`, `String`, `Vec`, `Map`, `Set`...\n", "\n", "But what if I want to store a Python object in my e-graph?\n" ] }, { "cell_type": "code", "execution_count": 61, "id": "be92f5ff-caf3-492e-a338-2db7e559cc2b", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [ { "data": { "text/plain": [ "PyObject(277923772, 1)" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph = EGraph()\n", "res = egraph.save_object(True)\n", "# Saves reference to object and stores in e-graph as type and value hashes:\n", "res" ] }, { "cell_type": "code", "execution_count": 22, "id": "e207b2d9-533d-4e04-9c22-2856fe306385", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph.load_object(res)" ] }, { "cell_type": "markdown", "id": "9c7986e4-0868-4489-8b66-3a30100c548d", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "Can eval arbitrary python code:\n" ] }, { "cell_type": "code", "execution_count": 62, "id": "d2c28413-a7f1-41ed-9675-5cf13bba9eba", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={}, _classes={}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {'py-object': set()}), _callable_ref_to_egg_fn={}, _egg_sort_to_type_ref={}, _type_ref_to_egg_sort={})))" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "empty_dict = egraph.save_object({})\n", "locals_ = empty_dict.dict_update(egraph.save_object(\"x\"), res)\n", "\n", "egraph.load_object(egraph.extract(py_eval(\"not x\", locals_, empty_dict)))" ] }, { "cell_type": "markdown", "id": "ee9e839d-d6c1-4161-af7b-b9db5cd42716", "metadata": { "editable": true, "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "### \"Preserved\" methods\n", "\n", "...from egglog to Python...\n" ] }, { "cell_type": "code", "execution_count": 24, "id": "26cf3d77-0013-4025-8db0-846eba404798", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ "egraph = EGraph()\n", "\n", "\n", "class Bool(Expr):\n", " def to_py(self) -> PyObject: ...\n", "\n", " def __or__(self, other: Bool) -> Bool: ...\n", "\n", " # This will get executed eagerly\n", " @egraph.method(preserve=True)\n", " def __bool__(self) -> bool:\n", " print(self)\n", " egraph.register(self)\n", " egraph.run(run(limit=10).saturate())\n", " print(f\" -> {egraph.extract(self)}\")\n", " return egraph.load_object(egraph.extract(self.to_py()))\n", "\n", "\n", "TRUE = egraph.constant(\"TRUE\", Bool)\n", "FALSE = egraph.constant(\"FALSE\", Bool)" ] }, { "cell_type": "code", "execution_count": 25, "id": "2034f106-2b50-4410-83d7-dd1feb8365ac", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "TRUE | FALSE\n", " -> TRUE | FALSE\n" ] }, { "ename": "EggSmolError", "evalue": "Not found: fake expression Bool.to_py [Value { tag: \"Bool\", bits: 2 }]", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mEggSmolError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[25], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;43mbool\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mTRUE\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m|\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mFALSE\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/runtime.py:403\u001b[0m, in \u001b[0;36m_preserved_method\u001b[0;34m(self, __name)\u001b[0m\n\u001b[1;32m 401\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m:\n\u001b[1;32m 402\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__egg_typed_expr__\u001b[38;5;241m.\u001b[39mtp\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m has no method \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m__name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m--> 403\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mmethod\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m)\u001b[49m\n", "Cell \u001b[0;32mIn[24], line 15\u001b[0m, in \u001b[0;36mBool.__bool__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 13\u001b[0m egraph\u001b[38;5;241m.\u001b[39mrun(run(limit\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m10\u001b[39m)\u001b[38;5;241m.\u001b[39msaturate())\n\u001b[1;32m 14\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m -> \u001b[39m\u001b[38;5;132;01m{\u001b[39;00megraph\u001b[38;5;241m.\u001b[39mextract(\u001b[38;5;28mself\u001b[39m)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m---> 15\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m egraph\u001b[38;5;241m.\u001b[39mload_object(\u001b[43megraph\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mextract\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_py\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m)\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/egraph.py:739\u001b[0m, in \u001b[0;36mEGraph.extract\u001b[0;34m(self, expr)\u001b[0m\n\u001b[1;32m 737\u001b[0m typed_expr \u001b[38;5;241m=\u001b[39m expr_parts(expr)\n\u001b[1;32m 738\u001b[0m egg_expr \u001b[38;5;241m=\u001b[39m typed_expr\u001b[38;5;241m.\u001b[39mto_egg(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_mod_decls)\n\u001b[0;32m--> 739\u001b[0m extract_report \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_run_extract\u001b[49m\u001b[43m(\u001b[49m\u001b[43megg_expr\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 740\u001b[0m new_typed_expr \u001b[38;5;241m=\u001b[39m TypedExprDecl\u001b[38;5;241m.\u001b[39mfrom_egg(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_mod_decls, extract_report\u001b[38;5;241m.\u001b[39mexpr)\n\u001b[1;32m 741\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m new_typed_expr\u001b[38;5;241m.\u001b[39mtp \u001b[38;5;241m!=\u001b[39m typed_expr\u001b[38;5;241m.\u001b[39mtp:\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/egraph.py:756\u001b[0m, in \u001b[0;36mEGraph._run_extract\u001b[0;34m(self, expr, n)\u001b[0m\n\u001b[1;32m 755\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_run_extract\u001b[39m(\u001b[38;5;28mself\u001b[39m, expr: bindings\u001b[38;5;241m.\u001b[39m_Expr, n: \u001b[38;5;28mint\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m bindings\u001b[38;5;241m.\u001b[39mExtractReport:\n\u001b[0;32m--> 756\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_process_commands\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43mbindings\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mExtract\u001b[49m\u001b[43m(\u001b[49m\u001b[43mn\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexpr\u001b[49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 757\u001b[0m extract_report \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_egraph\u001b[38;5;241m.\u001b[39mextract_report()\n\u001b[1;32m 758\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m extract_report:\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/egraph.py:634\u001b[0m, in \u001b[0;36mEGraph._process_commands\u001b[0;34m(self, commands)\u001b[0m\n\u001b[1;32m 633\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_process_commands\u001b[39m(\u001b[38;5;28mself\u001b[39m, commands: Iterable[bindings\u001b[38;5;241m.\u001b[39m_Command]) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 634\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_egraph\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_program\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mcommands\u001b[49m\u001b[43m)\u001b[49m\n", "\u001b[0;31mEggSmolError\u001b[0m: Not found: fake expression Bool.to_py [Value { tag: \"Bool\", bits: 2 }]" ] } ], "source": [ "bool(TRUE | FALSE)" ] }, { "cell_type": "code", "execution_count": 26, "id": "edc2fbb4-051e-4693-90c6-5f169c3f185a", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "TRUE | FALSE\n", " -> TRUE\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@egraph.register\n", "def _bool(x: Bool):\n", " return [\n", " set_(TRUE.to_py()).to(egraph.save_object(True)),\n", " set_(FALSE.to_py()).to(egraph.save_object(False)),\n", " rewrite(TRUE | x).to(TRUE),\n", " rewrite(FALSE | x).to(x),\n", " ]\n", "\n", "\n", "bool(TRUE | FALSE)" ] }, { "cell_type": "code", "execution_count": 27, "id": "ad299bd6-7dd2-4b22-8fa0-4135b486a7e2", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "TRUE | x\n", " -> TRUE\n", "it's true!\n" ] } ], "source": [ "x = egraph.constant(\"x\", Bool)\n", "if TRUE | x:\n", " print(\"it's true!\")" ] }, { "cell_type": "markdown", "id": "b995fd39-524f-4df3-a0fb-d7f882e5b00f", "metadata": { "editable": true, "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "### Conversions\n", "\n", "...from Python to egglog...\n" ] }, { "cell_type": "code", "execution_count": 28, "id": "a00b60cd-c34d-4ed7-ac24-f16678a00590", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [ { "data": { "text/plain": [ "TRUE | FALSE" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "converter(bool, Bool, lambda x: TRUE if x else FALSE)\n", "\n", "TRUE | False" ] }, { "cell_type": "markdown", "id": "cfc8d51a-5d48-49c5-b4e8-42d3706cab0b", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "- Allow you to do \"upcasting\" which is very common in Python\n", "- Can get closer to mimicking regular Python APIs\n" ] }, { "cell_type": "markdown", "id": "448931df-62ad-4391-8fa8-143ee68258a2", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "### Fib Example\n" ] }, { "cell_type": "code", "execution_count": 52, "id": "8599335e-19ec-4511-bced-77c7e4d05f68", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={'fib': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('x',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, _classes={'Num': ClassDecl(methods={'__add__': FunctionDecl(arg_types=(TypeRefWithVars(name='Num', args=()), TypeRefWithVars(name='Num', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_methods={'__init__': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('i',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {'Num.__init__': {ClassMethodRef(class_name='Num', method_name='__init__')}, 'Num.__add__': {MethodRef(class_name='Num', method_name='__add__')}, '!=': {MethodRef(class_name='Num', method_name='__ne__')}, 'fib': {FunctionRef(name='fib')}}), _callable_ref_to_egg_fn={ClassMethodRef(class_name='Num', method_name='__init__'): 'Num.__init__', MethodRef(class_name='Num', method_name='__add__'): 'Num.__add__', MethodRef(class_name='Num', method_name='__ne__'): '!=', FunctionRef(name='fib'): 'fib'}, _egg_sort_to_type_ref={'Num': JustTypeRef(name='Num', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Num', args=()): 'Num'})))" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph = EGraph()\n", "\n", "\n", "class Num(Expr):\n", " def __init__(self, i: i64Like) -> None: ...\n", "\n", " def __add__(self, other: Num) -> Num: ...\n", "\n", "\n", "@function\n", "def fib(x: i64Like) -> Num: ...\n", "\n", "\n", "@egraph.register\n", "def _fib(a: i64, b: i64, x: i64, f: Num):\n", " return [\n", " rewrite(Num(a) + Num(b)).to(Num(a + b)),\n", " rule(eq(f).to(fib(x)), x > 1).then(set_(fib(x)).to(fib(x - 1) + fib(x - 2))),\n", " set_(fib(0)).to(Num(0)),\n", " set_(fib(1)).to(Num(1)),\n", " ]\n", "\n", "\n", "egraph" ] }, { "cell_type": "code", "execution_count": 53, "id": "80aafdc2-90a6-46ef-b2a4-6559b26457f7", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196_0\n", "\n", "\n", "cluster_fib_5040379952546458196_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196:s->fib_5040379952546458196_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_0\n", "\n", "\n", "4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "f4_0\n", "\n", "\n", "f4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196_0\n", "\n", "\n", "cluster_fib_5040379952546458196_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196:s->fib_5040379952546458196_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_0\n", "\n", "\n", "4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "f4_0\n", "\n", "\n", "f4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={'fib': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('x',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, _classes={'Num': ClassDecl(methods={'__add__': FunctionDecl(arg_types=(TypeRefWithVars(name='Num', args=()), TypeRefWithVars(name='Num', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_methods={'__init__': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('i',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {'Num.__init__': {ClassMethodRef(class_name='Num', method_name='__init__')}, 'Num.__add__': {MethodRef(class_name='Num', method_name='__add__')}, '!=': {MethodRef(class_name='Num', method_name='__ne__')}, 'fib': {FunctionRef(name='fib')}}), _callable_ref_to_egg_fn={ClassMethodRef(class_name='Num', method_name='__init__'): 'Num.__init__', MethodRef(class_name='Num', method_name='__add__'): 'Num.__add__', MethodRef(class_name='Num', method_name='__ne__'): '!=', FunctionRef(name='fib'): 'fib'}, _egg_sort_to_type_ref={'Num': JustTypeRef(name='Num', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Num', args=()): 'Num'})))" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f4 = egraph.let(\"f4\", fib(4))\n", "egraph" ] }, { "cell_type": "code", "execution_count": 54, "id": "ebb3e6eb-bf39-49d8-9edd-0db5c04964d4", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_fib_17615343019692007359_0\n", "\n", "\n", "cluster_fib_17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196_0\n", "\n", "\n", "cluster_fib_5040379952546458196_0\n", "\n", "\n", "\n", "outer_cluster_fib_11743562013128004906_0\n", "\n", "\n", "cluster_fib_11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359:s->fib_17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196:s->fib_5040379952546458196_0\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906:s->fib_11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_0\n", "\n", "\n", "4\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "f4_0\n", "\n", "\n", "f4\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_fib_17615343019692007359_0\n", "\n", "\n", "cluster_fib_17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196_0\n", "\n", "\n", "cluster_fib_5040379952546458196_0\n", "\n", "\n", "\n", "outer_cluster_fib_11743562013128004906_0\n", "\n", "\n", "cluster_fib_11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359:s->fib_17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196:s->fib_5040379952546458196_0\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906:s->fib_11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_0\n", "\n", "\n", "4\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "f4_0\n", "\n", "\n", "f4\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={'fib': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('x',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, _classes={'Num': ClassDecl(methods={'__add__': FunctionDecl(arg_types=(TypeRefWithVars(name='Num', args=()), TypeRefWithVars(name='Num', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_methods={'__init__': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('i',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {'Num.__init__': {ClassMethodRef(class_name='Num', method_name='__init__')}, 'Num.__add__': {MethodRef(class_name='Num', method_name='__add__')}, '!=': {MethodRef(class_name='Num', method_name='__ne__')}, 'fib': {FunctionRef(name='fib')}}), _callable_ref_to_egg_fn={ClassMethodRef(class_name='Num', method_name='__init__'): 'Num.__init__', MethodRef(class_name='Num', method_name='__add__'): 'Num.__add__', MethodRef(class_name='Num', method_name='__ne__'): '!=', FunctionRef(name='fib'): 'fib'}, _egg_sort_to_type_ref={'Num': JustTypeRef(name='Num', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Num', args=()): 'Num'})))" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph.run(1)\n", "egraph" ] }, { "cell_type": "code", "execution_count": 55, "id": "908e3391-156f-4d4c-ac0f-8f059647e511", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196_0\n", "\n", "\n", "cluster_fib_5040379952546458196_0\n", "\n", "\n", "\n", "outer_cluster_fib_17615343019692007359_0\n", "\n", "\n", "cluster_fib_17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_fib_11743562013128004906_0\n", "\n", "\n", "cluster_fib_11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___956286968014291186:s->fib_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___956286968014291186:s->fib_5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906:s->fib_11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196:s->fib_5040379952546458196_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___6267377405668604861:s->Num.__init___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___6267377405668604861:s->Num.__add___956286968014291186\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359:s->fib_17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_0\n", "\n", "\n", "4\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___956286968014291186\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "f4_0\n", "\n", "\n", "f4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___6267377405668604861\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196_0\n", "\n", "\n", "cluster_fib_5040379952546458196_0\n", "\n", "\n", "\n", "outer_cluster_fib_17615343019692007359_0\n", "\n", "\n", "cluster_fib_17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_fib_11743562013128004906_0\n", "\n", "\n", "cluster_fib_11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___956286968014291186:s->fib_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___956286968014291186:s->fib_5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906:s->fib_11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196:s->fib_5040379952546458196_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___6267377405668604861:s->Num.__init___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___6267377405668604861:s->Num.__add___956286968014291186\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359:s->fib_17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_0\n", "\n", "\n", "4\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___956286968014291186\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "f4_0\n", "\n", "\n", "f4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___6267377405668604861\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={'fib': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('x',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, _classes={'Num': ClassDecl(methods={'__add__': FunctionDecl(arg_types=(TypeRefWithVars(name='Num', args=()), TypeRefWithVars(name='Num', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_methods={'__init__': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('i',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {'Num.__init__': {ClassMethodRef(class_name='Num', method_name='__init__')}, 'Num.__add__': {MethodRef(class_name='Num', method_name='__add__')}, '!=': {MethodRef(class_name='Num', method_name='__ne__')}, 'fib': {FunctionRef(name='fib')}}), _callable_ref_to_egg_fn={ClassMethodRef(class_name='Num', method_name='__init__'): 'Num.__init__', MethodRef(class_name='Num', method_name='__add__'): 'Num.__add__', MethodRef(class_name='Num', method_name='__ne__'): '!=', FunctionRef(name='fib'): 'fib'}, _egg_sort_to_type_ref={'Num': JustTypeRef(name='Num', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Num', args=()): 'Num'})))" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph.run(1)\n", "egraph" ] }, { "cell_type": "code", "execution_count": 56, "id": "cf868ab3-c0ff-4719-9b95-e937e61ebd2d", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_fib_17615343019692007359_0\n", "\n", "\n", "cluster_fib_17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196_0\n", "\n", "\n", "cluster_fib_5040379952546458196_0\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_11743562013128004906_0\n", "\n", "\n", "cluster_fib_11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408:s->fib_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408:s->fib_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906:s->fib_11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196:s->fib_5040379952546458196_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604:s->Num.__add___395596399104602408\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604:s->Num.__init___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359:s->fib_17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_0\n", "\n", "\n", "4\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "f4_0\n", "\n", "\n", "f4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_fib_17615343019692007359_0\n", "\n", "\n", "cluster_fib_17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196_0\n", "\n", "\n", "cluster_fib_5040379952546458196_0\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_11743562013128004906_0\n", "\n", "\n", "cluster_fib_11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408:s->fib_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408:s->fib_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906:s->fib_11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196:s->fib_5040379952546458196_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604:s->Num.__add___395596399104602408\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604:s->Num.__init___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359:s->fib_17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_0\n", "\n", "\n", "4\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "f4_0\n", "\n", "\n", "f4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={'fib': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('x',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, _classes={'Num': ClassDecl(methods={'__add__': FunctionDecl(arg_types=(TypeRefWithVars(name='Num', args=()), TypeRefWithVars(name='Num', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_methods={'__init__': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('i',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {'Num.__init__': {ClassMethodRef(class_name='Num', method_name='__init__')}, 'Num.__add__': {MethodRef(class_name='Num', method_name='__add__')}, '!=': {MethodRef(class_name='Num', method_name='__ne__')}, 'fib': {FunctionRef(name='fib')}}), _callable_ref_to_egg_fn={ClassMethodRef(class_name='Num', method_name='__init__'): 'Num.__init__', MethodRef(class_name='Num', method_name='__add__'): 'Num.__add__', MethodRef(class_name='Num', method_name='__ne__'): '!=', FunctionRef(name='fib'): 'fib'}, _egg_sort_to_type_ref={'Num': JustTypeRef(name='Num', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Num', args=()): 'Num'})))" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph.run(1)\n", "egraph" ] }, { "cell_type": "code", "execution_count": 57, "id": "9283b1d4-f83d-4796-98b7-de1b4e5b2a67", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_fib_17615343019692007359_0\n", "\n", "\n", "cluster_fib_17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_fib_11743562013128004906_0\n", "\n", "\n", "cluster_fib_11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196_0\n", "\n", "\n", "cluster_fib_5040379952546458196_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408:s->fib_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408:s->fib_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906:s->fib_11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196:s->fib_5040379952546458196_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604:s->Num.__add___395596399104602408\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604:s->Num.__init___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906:s->Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359:s->fib_17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_0\n", "\n", "\n", "4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "f4_0\n", "\n", "\n", "f4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_fib_17615343019692007359_0\n", "\n", "\n", "cluster_fib_17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_fib_11743562013128004906_0\n", "\n", "\n", "cluster_fib_11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196_0\n", "\n", "\n", "cluster_fib_5040379952546458196_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408:s->fib_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408:s->fib_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906:s->fib_11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196:s->fib_5040379952546458196_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604:s->Num.__add___395596399104602408\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604:s->Num.__init___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906:s->Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359:s->fib_17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_0\n", "\n", "\n", "4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "f4_0\n", "\n", "\n", "f4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={'fib': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('x',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, _classes={'Num': ClassDecl(methods={'__add__': FunctionDecl(arg_types=(TypeRefWithVars(name='Num', args=()), TypeRefWithVars(name='Num', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_methods={'__init__': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('i',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {'Num.__init__': {ClassMethodRef(class_name='Num', method_name='__init__')}, 'Num.__add__': {MethodRef(class_name='Num', method_name='__add__')}, '!=': {MethodRef(class_name='Num', method_name='__ne__')}, 'fib': {FunctionRef(name='fib')}}), _callable_ref_to_egg_fn={ClassMethodRef(class_name='Num', method_name='__init__'): 'Num.__init__', MethodRef(class_name='Num', method_name='__add__'): 'Num.__add__', MethodRef(class_name='Num', method_name='__ne__'): '!=', FunctionRef(name='fib'): 'fib'}, _egg_sort_to_type_ref={'Num': JustTypeRef(name='Num', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Num', args=()): 'Num'})))" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph.run(1)\n", "egraph" ] }, { "cell_type": "code", "execution_count": 59, "id": "0aef5e81-43e3-4001-bf7a-b692fb3ff4b4", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Num(3)\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_fib_17615343019692007359_0\n", "\n", "\n", "cluster_fib_17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_fib_11743562013128004906_0\n", "\n", "\n", "cluster_fib_11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196_0\n", "\n", "\n", "cluster_fib_5040379952546458196_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___17615343019692007359_0\n", "\n", "\n", "cluster_Num.__init___17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408:s->fib_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408:s->fib_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906:s->fib_11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359:s->Num.__init___17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196:s->fib_5040379952546458196_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604:s->Num.__add___395596399104602408\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604:s->Num.__init___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906:s->Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359:s->fib_17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_0\n", "\n", "\n", "4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "f4_0\n", "\n", "\n", "f4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "cluster_Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_fib_17615343019692007359_0\n", "\n", "\n", "cluster_fib_17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_fib_11743562013128004906_0\n", "\n", "\n", "cluster_fib_11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___0_0\n", "\n", "\n", "cluster_Num.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5871781006564002453_0\n", "\n", "\n", "cluster_fib_5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_fib_0_0\n", "\n", "\n", "cluster_fib_0_0\n", "\n", "\n", "\n", "outer_cluster_fib_5040379952546458196_0\n", "\n", "\n", "cluster_fib_5040379952546458196_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "cluster_Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "outer_cluster_Num.__init___17615343019692007359_0\n", "\n", "\n", "cluster_Num.__init___17615343019692007359_0\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_4\n", "\n", "\n", "cluster_4\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_3\n", "\n", "\n", "cluster_3\n", "\n", "\n", "\n", "\n", "Num.__init___0:s->Num.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "fib_0:s->fib_0_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408:s->fib_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408:s->fib_11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453:s->Num.__init___5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906:s->fib_11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453:s->fib_5871781006564002453_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978:s->fib_17615343019692007359\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359:s->Num.__init___17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196:s->fib_5040379952546458196_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604:s->Num.__add___395596399104602408\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604:s->Num.__init___5871781006564002453\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906:s->Num.__init___11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359:s->fib_17615343019692007359_0\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906_0\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196_0\n", "\n", "\n", "4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453_0\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359_0\n", "\n", "\n", "3\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___0\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_0\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___395596399104602408\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___5871781006564002453\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_11743562013128004906\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5871781006564002453\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___16275225025205966978\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___17615343019692007359\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_5040379952546458196\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n", "f4_0\n", "\n", "\n", "f4\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__add___5435976351651060604\n", "\n", "\n", "Num.__add__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Num.__init___11743562013128004906\n", "\n", "\n", "Num.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "fib_17615343019692007359\n", "\n", "\n", "fib\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={'fib': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('x',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, _classes={'Num': ClassDecl(methods={'__add__': FunctionDecl(arg_types=(TypeRefWithVars(name='Num', args=()), TypeRefWithVars(name='Num', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_methods={'__init__': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('i',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Num', args=()), var_arg_type=None)}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {'Num.__init__': {ClassMethodRef(class_name='Num', method_name='__init__')}, 'Num.__add__': {MethodRef(class_name='Num', method_name='__add__')}, '!=': {MethodRef(class_name='Num', method_name='__ne__')}, 'fib': {FunctionRef(name='fib')}}), _callable_ref_to_egg_fn={ClassMethodRef(class_name='Num', method_name='__init__'): 'Num.__init__', MethodRef(class_name='Num', method_name='__add__'): 'Num.__add__', MethodRef(class_name='Num', method_name='__ne__'): '!=', FunctionRef(name='fib'): 'fib'}, _egg_sort_to_type_ref={'Num': JustTypeRef(name='Num', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Num', args=()): 'Num'})))" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph.run(1)\n", "print(egraph.extract(f4))\n", "egraph" ] }, { "cell_type": "markdown", "id": "a037bf31-2637-470a-ae26-b56538f689a6", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "### A story about Arrays\n" ] }, { "cell_type": "markdown", "id": "082d9334-86e2-42a1-92f4-08563902b064", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- This is one path through a huge maze of use cases.\n", "- Does not represent one killer example, but is an area I am familar with based on my previous work\n" ] }, { "cell_type": "markdown", "id": "24955a1a-d3d6-44d8-a7ee-b5a87bd2a153", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "#### 1. Someone makes an NDArray library...\n" ] }, { "cell_type": "code", "execution_count": 29, "id": "be2f1cb2-81c1-485d-8eb9-06c4d8b3c6ba", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ "ndarray_mod = Module()" ] }, { "cell_type": "code", "execution_count": 30, "id": "b0d83999-9aac-4881-a81a-385541b621fb", "metadata": { "editable": true, "slideshow": { "slide_type": "skip" }, "tags": [] }, "outputs": [], "source": [ "@ndarray_mod.class_\n", "class Value(Expr):\n", " def __init__(self, v: i64Like) -> None: ...\n", "\n", " def __mul__(self, other: Value) -> Value: ...\n", "\n", " def __add__(self, other: Value) -> Value: ...\n", "\n", "\n", "i, j = vars_(\"i j\", i64)\n", "ndarray_mod.register(\n", " rewrite(Value(i) * Value(j)).to(Value(i * j)),\n", " rewrite(Value(i) + Value(j)).to(Value(i + j)),\n", ")\n", "\n", "\n", "@ndarray_mod.class_\n", "class Values(Expr):\n", " def __init__(self, v: Vec[Value]) -> None: ...\n", "\n", " def __getitem__(self, idx: Value) -> Value: ...\n", "\n", " def length(self) -> Value: ...\n", "\n", " def concat(self, other: Values) -> Values: ...\n", "\n", "\n", "@ndarray_mod.register\n", "def _values(vs: Vec[Value], other: Vec[Value]):\n", " yield rewrite(Values(vs)[Value(i)]).to(vs[i])\n", " yield rewrite(Values(vs).length()).to(Value(vs.length()))\n", " yield rewrite(Values(vs).concat(Values(other))).to(Values(vs.append(other)))" ] }, { "cell_type": "code", "execution_count": 31, "id": "0a9c6dfd-21b6-4e28-abe4-1bc8d8229a5a", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ "@ndarray_mod.class_\n", "class NDArray(Expr):\n", " def __getitem__(self, idx: Values) -> Value: ...\n", "\n", " def shape(self) -> Values: ...\n", "\n", "\n", "@ndarray_mod.function\n", "def arange(n: Value) -> NDArray: ..." ] }, { "cell_type": "markdown", "id": "36dd2603-c60e-42d0-a5d5-98043ed307a5", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Basic\n", "- One function, range, get shape and index into array\n", "- Very different from existing paradigms in Python... Inheritance, multi-dispatch, dunder protocols.\n", " - Entirely open protocol.\n", " - Anyone else could define ways to create arrays\n", " - About mathematical definition really. This is from M\n" ] }, { "attachments": {}, "cell_type": "markdown", "id": "0f36b591-9a20-4405-80cb-3dbfea11b129", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "source": [ "Restifo Mullin, Lenore Marie, \"A mathematics of arrays\" (1988). _Electrical Engineering and Computer Science - Dissertations_. 249.\n" ] }, { "cell_type": "code", "execution_count": 32, "id": "3e020ae8-29a3-4e35-8510-aa2639c87701", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ "@ndarray_mod.register\n", "def _(n: Value, idx: Values, a: NDArray):\n", " yield rewrite(arange(n).shape()).to(Values(Vec(n)))\n", " yield rewrite(arange(n)[idx]).to(idx[Value(0)])" ] }, { "cell_type": "markdown", "id": "81562baf-da04-4734-bc79-b0aedf11ab02", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Rules to compute shape and index into arange.\n" ] }, { "cell_type": "code", "execution_count": 33, "id": "d46c1977-fa8c-4410-90c6-619ef3659a87", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Value.__init___3377577844511369682_0\n", "\n", "\n", "cluster_Value.__init___3377577844511369682_0\n", "\n", "\n", "\n", "outer_cluster_Values.__init___0_0\n", "\n", "\n", "cluster_Values.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "\n", "Values.__init___0_0:s->Value.__init___3377577844511369682\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___0:s->Values.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "NDArray.shape_5871781006564002453:s->ten_0\n", "\n", "\n", "\n", "\n", "\n", "arange_0:s->Value.__init___3377577844511369682\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___3377577844511369682:s->Value.__init___3377577844511369682_0\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___3377577844511369682_0\n", "\n", "\n", "10\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___0_0\n", "\n", "\n", "Vec[Value]\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___0\n", "\n", "\n", "Values.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "NDArray.shape_5871781006564002453\n", "\n", "\n", "NDArray.shape\n", "\n", "\n", "\n", "\n", "\n", "\n", "arange_0\n", "\n", "\n", "arange\n", "\n", "\n", "\n", "\n", "\n", "\n", "ten_0\n", "\n", "\n", "ten\n", "\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___3377577844511369682\n", "\n", "\n", "Value.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Value.__init___3377577844511369682_0\n", "\n", "\n", "cluster_Value.__init___3377577844511369682_0\n", "\n", "\n", "\n", "outer_cluster_Values.__init___0_0\n", "\n", "\n", "cluster_Values.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "\n", "Values.__init___0_0:s->Value.__init___3377577844511369682\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___0:s->Values.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "NDArray.shape_5871781006564002453:s->ten_0\n", "\n", "\n", "\n", "\n", "\n", "arange_0:s->Value.__init___3377577844511369682\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___3377577844511369682:s->Value.__init___3377577844511369682_0\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___3377577844511369682_0\n", "\n", "\n", "10\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___0_0\n", "\n", "\n", "Vec[Value]\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___0\n", "\n", "\n", "Values.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "NDArray.shape_5871781006564002453\n", "\n", "\n", "NDArray.shape\n", "\n", "\n", "\n", "\n", "\n", "\n", "arange_0\n", "\n", "\n", "arange\n", "\n", "\n", "\n", "\n", "\n", "\n", "ten_0\n", "\n", "\n", "ten\n", "\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___3377577844511369682\n", "\n", "\n", "Value.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[Module(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={'arange': FunctionDecl(arg_types=(TypeRefWithVars(name='Value', args=()),), arg_names=('n',), arg_defaults=(None,), return_type=TypeRefWithVars(name='NDArray', args=()), var_arg_type=None)}, _classes={'Value': ClassDecl(methods={'__mul__': FunctionDecl(arg_types=(TypeRefWithVars(name='Value', args=()), TypeRefWithVars(name='Value', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Value', args=()), var_arg_type=None), '__add__': FunctionDecl(arg_types=(TypeRefWithVars(name='Value', args=()), TypeRefWithVars(name='Value', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Value', args=()), var_arg_type=None)}, class_methods={'__init__': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('v',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Value', args=()), var_arg_type=None)}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0), 'Values': ClassDecl(methods={'__getitem__': FunctionDecl(arg_types=(TypeRefWithVars(name='Values', args=()), TypeRefWithVars(name='Value', args=())), arg_names=('self', 'idx'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Value', args=()), var_arg_type=None), 'length': FunctionDecl(arg_types=(TypeRefWithVars(name='Values', args=()),), arg_names=('self',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Value', args=()), var_arg_type=None), 'concat': FunctionDecl(arg_types=(TypeRefWithVars(name='Values', args=()), TypeRefWithVars(name='Values', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Values', args=()), var_arg_type=None)}, class_methods={'__init__': FunctionDecl(arg_types=(TypeRefWithVars(name='Vec', args=(TypeRefWithVars(name='Value', args=()),)),), arg_names=('v',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Values', args=()), var_arg_type=None)}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0), 'NDArray': ClassDecl(methods={'__getitem__': FunctionDecl(arg_types=(TypeRefWithVars(name='NDArray', args=()), TypeRefWithVars(name='Values', args=())), arg_names=('self', 'idx'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Value', args=()), var_arg_type=None), 'shape': FunctionDecl(arg_types=(TypeRefWithVars(name='NDArray', args=()),), arg_names=('self',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Values', args=()), var_arg_type=None)}, class_methods={}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {'Value.__init__': {ClassMethodRef(class_name='Value', method_name='__init__')}, 'Value.__mul__': {MethodRef(class_name='Value', method_name='__mul__')}, 'Value.__add__': {MethodRef(class_name='Value', method_name='__add__')}, '!=': {MethodRef(class_name='NDArray', method_name='__ne__'), MethodRef(class_name='Values', method_name='__ne__'), MethodRef(class_name='Value', method_name='__ne__')}, 'Values.__init__': {ClassMethodRef(class_name='Values', method_name='__init__')}, 'Values.__getitem__': {MethodRef(class_name='Values', method_name='__getitem__')}, 'Values.length': {MethodRef(class_name='Values', method_name='length')}, 'Values.concat': {MethodRef(class_name='Values', method_name='concat')}, 'NDArray.__getitem__': {MethodRef(class_name='NDArray', method_name='__getitem__')}, 'NDArray.shape': {MethodRef(class_name='NDArray', method_name='shape')}, 'arange': {FunctionRef(name='arange')}}), _callable_ref_to_egg_fn={ClassMethodRef(class_name='Value', method_name='__init__'): 'Value.__init__', MethodRef(class_name='Value', method_name='__mul__'): 'Value.__mul__', MethodRef(class_name='Value', method_name='__add__'): 'Value.__add__', MethodRef(class_name='Value', method_name='__ne__'): '!=', ClassMethodRef(class_name='Values', method_name='__init__'): 'Values.__init__', MethodRef(class_name='Values', method_name='__getitem__'): 'Values.__getitem__', MethodRef(class_name='Values', method_name='length'): 'Values.length', MethodRef(class_name='Values', method_name='concat'): 'Values.concat', MethodRef(class_name='Values', method_name='__ne__'): '!=', MethodRef(class_name='NDArray', method_name='__getitem__'): 'NDArray.__getitem__', MethodRef(class_name='NDArray', method_name='shape'): 'NDArray.shape', MethodRef(class_name='NDArray', method_name='__ne__'): '!=', FunctionRef(name='arange'): 'arange'}, _egg_sort_to_type_ref={'Value': JustTypeRef(name='Value', args=()), 'Values': JustTypeRef(name='Values', args=()), 'Vec[Value]': JustTypeRef(name='Vec', args=(JustTypeRef(name='Value', args=()),)), 'NDArray': JustTypeRef(name='NDArray', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Value', args=()): 'Value', JustTypeRef(name='Values', args=()): 'Values', JustTypeRef(name='Vec', args=(JustTypeRef(name='Value', args=()),)): 'Vec[Value]', JustTypeRef(name='NDArray', args=()): 'NDArray'})))], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={}, _classes={}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {}), _callable_ref_to_egg_fn={}, _egg_sort_to_type_ref={}, _type_ref_to_egg_sort={})))" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Values(Vec.empty().push(Value(10)))" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph = EGraph([ndarray_mod])\n", "ten = egraph.let(\"ten\", arange(Value(10)))\n", "ten_shape = ten.shape()\n", "egraph.register(ten_shape)\n", "\n", "egraph.run(20)\n", "egraph.display()\n", "egraph.extract(ten_shape)" ] }, { "cell_type": "code", "execution_count": 34, "id": "7a0d38d8-085a-4c61-ab23-06247c7171ef", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Value.__init___3377577844511369682_0\n", "\n", "\n", "cluster_Value.__init___3377577844511369682_0\n", "\n", "\n", "\n", "outer_cluster_Value.__init___0_0\n", "\n", "\n", "cluster_Value.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_Values.__init___11743562013128004906_0\n", "\n", "\n", "cluster_Values.__init___11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Value.__init___4208978898528913939_0\n", "\n", "\n", "cluster_Value.__init___4208978898528913939_0\n", "\n", "\n", "\n", "outer_cluster_Values.__init___0_0\n", "\n", "\n", "cluster_Values.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_5\n", "\n", "\n", "cluster_5\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_6\n", "\n", "\n", "cluster_6\n", "\n", "\n", "\n", "outer_cluster_7\n", "\n", "\n", "cluster_7\n", "\n", "\n", "\n", "\n", "Values.__init___0_0:s->Value.__init___3377577844511369682\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___11743562013128004906_0:s->NDArray.__getitem___11868447927124751835\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___0:s->Values.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "NDArray.shape_5871781006564002453:s->arange_0\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___11743562013128004906:s->Values.__init___11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "arange_0:s->Value.__init___3377577844511369682\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___3377577844511369682:s->Value.__init___3377577844511369682_0\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___4208978898528913939:s->Value.__init___4208978898528913939_0\n", "\n", "\n", "\n", "\n", "\n", "Values.__getitem___520482313101349337:s->Values.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Values.__getitem___520482313101349337:s->Value.__init___0\n", "\n", "\n", "\n", "\n", "\n", "NDArray.__getitem___11868447927124751835:s->Values.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "NDArray.__getitem___11868447927124751835:s->ten_0\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___0:s->Value.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___3377577844511369682_0\n", "\n", "\n", "10\n", "\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___4208978898528913939_0\n", "\n", "\n", "7\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___0_0\n", "\n", "\n", "Vec[Value]\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___11743562013128004906_0\n", "\n", "\n", "Vec[Value]\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___0\n", "\n", "\n", "Values.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "NDArray.shape_5871781006564002453\n", "\n", "\n", "NDArray.shape\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___11743562013128004906\n", "\n", "\n", "Values.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "arange_0\n", "\n", "\n", "arange\n", "\n", "\n", "\n", "\n", "\n", "\n", "ten_0\n", "\n", "\n", "ten\n", "\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___3377577844511369682\n", "\n", "\n", "Value.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___4208978898528913939\n", "\n", "\n", "Value.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__getitem___520482313101349337\n", "\n", "\n", "Values.__getitem__\n", "\n", "\n", "\n", "\n", "\n", "\n", "NDArray.__getitem___11868447927124751835\n", "\n", "\n", "NDArray.__getitem__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___0\n", "\n", "\n", "Value.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "outer_cluster_Value.__init___3377577844511369682_0\n", "\n", "\n", "cluster_Value.__init___3377577844511369682_0\n", "\n", "\n", "\n", "outer_cluster_Value.__init___0_0\n", "\n", "\n", "cluster_Value.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_Values.__init___11743562013128004906_0\n", "\n", "\n", "cluster_Values.__init___11743562013128004906_0\n", "\n", "\n", "\n", "outer_cluster_Value.__init___4208978898528913939_0\n", "\n", "\n", "cluster_Value.__init___4208978898528913939_0\n", "\n", "\n", "\n", "outer_cluster_Values.__init___0_0\n", "\n", "\n", "cluster_Values.__init___0_0\n", "\n", "\n", "\n", "outer_cluster_2\n", "\n", "\n", "cluster_2\n", "\n", "\n", "\n", "outer_cluster_5\n", "\n", "\n", "cluster_5\n", "\n", "\n", "\n", "outer_cluster_1\n", "\n", "\n", "cluster_1\n", "\n", "\n", "\n", "outer_cluster_0\n", "\n", "\n", "cluster_0\n", "\n", "\n", "\n", "outer_cluster_6\n", "\n", "\n", "cluster_6\n", "\n", "\n", "\n", "outer_cluster_7\n", "\n", "\n", "cluster_7\n", "\n", "\n", "\n", "\n", "Values.__init___0_0:s->Value.__init___3377577844511369682\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___11743562013128004906_0:s->NDArray.__getitem___11868447927124751835\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___0:s->Values.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "NDArray.shape_5871781006564002453:s->arange_0\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___11743562013128004906:s->Values.__init___11743562013128004906_0\n", "\n", "\n", "\n", "\n", "\n", "arange_0:s->Value.__init___3377577844511369682\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___3377577844511369682:s->Value.__init___3377577844511369682_0\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___4208978898528913939:s->Value.__init___4208978898528913939_0\n", "\n", "\n", "\n", "\n", "\n", "Values.__getitem___520482313101349337:s->Values.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "Values.__getitem___520482313101349337:s->Value.__init___0\n", "\n", "\n", "\n", "\n", "\n", "NDArray.__getitem___11868447927124751835:s->Values.__init___11743562013128004906\n", "\n", "\n", "\n", "\n", "\n", "NDArray.__getitem___11868447927124751835:s->ten_0\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___0:s->Value.__init___0_0\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___3377577844511369682_0\n", "\n", "\n", "10\n", "\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___0_0\n", "\n", "\n", "0\n", "\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___4208978898528913939_0\n", "\n", "\n", "7\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___0_0\n", "\n", "\n", "Vec[Value]\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___11743562013128004906_0\n", "\n", "\n", "Vec[Value]\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___0\n", "\n", "\n", "Values.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "NDArray.shape_5871781006564002453\n", "\n", "\n", "NDArray.shape\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__init___11743562013128004906\n", "\n", "\n", "Values.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "arange_0\n", "\n", "\n", "arange\n", "\n", "\n", "\n", "\n", "\n", "\n", "ten_0\n", "\n", "\n", "ten\n", "\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___3377577844511369682\n", "\n", "\n", "Value.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___4208978898528913939\n", "\n", "\n", "Value.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Values.__getitem___520482313101349337\n", "\n", "\n", "Values.__getitem__\n", "\n", "\n", "\n", "\n", "\n", "\n", "NDArray.__getitem___11868447927124751835\n", "\n", "\n", "NDArray.__getitem__\n", "\n", "\n", "\n", "\n", "\n", "\n", "Value.__init___0\n", "\n", "\n", "Value.__init__\n", "\n", "\n", "\n", "\n", "\n", "\n" ], "text/plain": [ "EGraph(_flatted_deps=[Module(_flatted_deps=[], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={'arange': FunctionDecl(arg_types=(TypeRefWithVars(name='Value', args=()),), arg_names=('n',), arg_defaults=(None,), return_type=TypeRefWithVars(name='NDArray', args=()), var_arg_type=None)}, _classes={'Value': ClassDecl(methods={'__mul__': FunctionDecl(arg_types=(TypeRefWithVars(name='Value', args=()), TypeRefWithVars(name='Value', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Value', args=()), var_arg_type=None), '__add__': FunctionDecl(arg_types=(TypeRefWithVars(name='Value', args=()), TypeRefWithVars(name='Value', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Value', args=()), var_arg_type=None)}, class_methods={'__init__': FunctionDecl(arg_types=(TypeRefWithVars(name='i64', args=()),), arg_names=('v',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Value', args=()), var_arg_type=None)}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0), 'Values': ClassDecl(methods={'__getitem__': FunctionDecl(arg_types=(TypeRefWithVars(name='Values', args=()), TypeRefWithVars(name='Value', args=())), arg_names=('self', 'idx'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Value', args=()), var_arg_type=None), 'length': FunctionDecl(arg_types=(TypeRefWithVars(name='Values', args=()),), arg_names=('self',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Value', args=()), var_arg_type=None), 'concat': FunctionDecl(arg_types=(TypeRefWithVars(name='Values', args=()), TypeRefWithVars(name='Values', args=())), arg_names=('self', 'other'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Values', args=()), var_arg_type=None)}, class_methods={'__init__': FunctionDecl(arg_types=(TypeRefWithVars(name='Vec', args=(TypeRefWithVars(name='Value', args=()),)),), arg_names=('v',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Values', args=()), var_arg_type=None)}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0), 'NDArray': ClassDecl(methods={'__getitem__': FunctionDecl(arg_types=(TypeRefWithVars(name='NDArray', args=()), TypeRefWithVars(name='Values', args=())), arg_names=('self', 'idx'), arg_defaults=(None, None), return_type=TypeRefWithVars(name='Value', args=()), var_arg_type=None), 'shape': FunctionDecl(arg_types=(TypeRefWithVars(name='NDArray', args=()),), arg_names=('self',), arg_defaults=(None,), return_type=TypeRefWithVars(name='Values', args=()), var_arg_type=None)}, class_methods={}, class_variables={}, properties={}, preserved_methods={}, n_type_vars=0)}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {'Value.__init__': {ClassMethodRef(class_name='Value', method_name='__init__')}, 'Value.__mul__': {MethodRef(class_name='Value', method_name='__mul__')}, 'Value.__add__': {MethodRef(class_name='Value', method_name='__add__')}, '!=': {MethodRef(class_name='NDArray', method_name='__ne__'), MethodRef(class_name='Values', method_name='__ne__'), MethodRef(class_name='Value', method_name='__ne__')}, 'Values.__init__': {ClassMethodRef(class_name='Values', method_name='__init__')}, 'Values.__getitem__': {MethodRef(class_name='Values', method_name='__getitem__')}, 'Values.length': {MethodRef(class_name='Values', method_name='length')}, 'Values.concat': {MethodRef(class_name='Values', method_name='concat')}, 'NDArray.__getitem__': {MethodRef(class_name='NDArray', method_name='__getitem__')}, 'NDArray.shape': {MethodRef(class_name='NDArray', method_name='shape')}, 'arange': {FunctionRef(name='arange')}}), _callable_ref_to_egg_fn={ClassMethodRef(class_name='Value', method_name='__init__'): 'Value.__init__', MethodRef(class_name='Value', method_name='__mul__'): 'Value.__mul__', MethodRef(class_name='Value', method_name='__add__'): 'Value.__add__', MethodRef(class_name='Value', method_name='__ne__'): '!=', ClassMethodRef(class_name='Values', method_name='__init__'): 'Values.__init__', MethodRef(class_name='Values', method_name='__getitem__'): 'Values.__getitem__', MethodRef(class_name='Values', method_name='length'): 'Values.length', MethodRef(class_name='Values', method_name='concat'): 'Values.concat', MethodRef(class_name='Values', method_name='__ne__'): '!=', MethodRef(class_name='NDArray', method_name='__getitem__'): 'NDArray.__getitem__', MethodRef(class_name='NDArray', method_name='shape'): 'NDArray.shape', MethodRef(class_name='NDArray', method_name='__ne__'): '!=', FunctionRef(name='arange'): 'arange'}, _egg_sort_to_type_ref={'Value': JustTypeRef(name='Value', args=()), 'Values': JustTypeRef(name='Values', args=()), 'Vec[Value]': JustTypeRef(name='Vec', args=(JustTypeRef(name='Value', args=()),)), 'NDArray': JustTypeRef(name='NDArray', args=())}, _type_ref_to_egg_sort={JustTypeRef(name='Value', args=()): 'Value', JustTypeRef(name='Values', args=()): 'Values', JustTypeRef(name='Vec', args=(JustTypeRef(name='Value', args=()),)): 'Vec[Value]', JustTypeRef(name='NDArray', args=()): 'NDArray'})))], _mod_decls=ModuleDeclarations(_decl=Declarations(_functions={}, _classes={}, _constants={}, _egg_fn_to_callable_refs=defaultdict(, {'vec-empty': set(), 'Value.__init__': set(), 'vec-push': set(), 'Values.__init__': set()}), _callable_ref_to_egg_fn={}, _egg_sort_to_type_ref={}, _type_ref_to_egg_sort={})))" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Value(7)" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ten_indexed = ten[Values(Vec(Value(7)))]\n", "egraph.register(ten_indexed)\n", "\n", "egraph.run(20)\n", "\n", "egraph.display()\n", "egraph.extract(ten_indexed)" ] }, { "cell_type": "markdown", "id": "956f439e-80e6-4ff3-adb2-52a784ee5902", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Any user can try it now\n" ] }, { "cell_type": "markdown", "id": "07bece32-f436-4c6b-8d8a-21305673b376", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "#### 2. Someone else decides to implement a cross product library\n" ] }, { "cell_type": "code", "execution_count": 35, "id": "0eecf615-36c1-44a6-b122-743f66bc997f", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ "cross_mod = Module([ndarray_mod])\n", "\n", "\n", "@cross_mod.function\n", "def cross(l: NDArray, r: NDArray) -> NDArray: ...\n", "\n", "\n", "@cross_mod.register\n", "def _cross(l: NDArray, r: NDArray, idx: Values):\n", " yield rewrite(cross(l, r).shape()).to(l.shape().concat(r.shape()))\n", " # Just noticed this is wrong!\n", " yield rewrite(cross(l, r)[idx]).to(l[idx] * r[idx])" ] }, { "cell_type": "markdown", "id": "d1a60f2d-5669-4c05-be64-68f525eae9e4", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Someone decides to add some functionality\n", "- Multiplicative cross product\n", "- Shape is concatation, index is product of each matrix at that index\n", "- Mathematical definition\n" ] }, { "cell_type": "code", "execution_count": 36, "id": "a7127ee6-2d17-4460-942a-b303277d8f81", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [ { "data": { "text/plain": [ "Values(Vec.empty().push(Value(11)).push(Value(10)))" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph = EGraph([cross_mod])\n", "egraph.simplify(cross(arange(Value(10)), arange(Value(11))).shape(), 10)" ] }, { "cell_type": "markdown", "id": "944b5b6c-7583-4c75-a740-0d75a835c522", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "#### 3. I write my wonderful data science application using it\n" ] }, { "cell_type": "code", "execution_count": 37, "id": "14fde972-d358-4324-bc1e-35b3591184cc", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [ { "data": { "text/plain": [ "Value(100)" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def my_special_app(x: Value) -> Value:\n", " return cross(arange(x), arange(x))[Values(Vec(x))]\n", "\n", "\n", "egraph = EGraph([cross_mod])\n", "\n", "egraph.simplify(my_special_app(Value(10)), 10)" ] }, { "cell_type": "markdown", "id": "9f39ea1c-689d-4f5c-9fc3-bb8bd79e44f7", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Different person installs cross module\n", "- Implements application using their complicated algorithm\n" ] }, { "cell_type": "markdown", "id": "6967505c-48f0-45ad-837e-b6f2fdc99921", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "source": [ ".... but its too slow...\n" ] }, { "cell_type": "code", "execution_count": 38, "id": "12a435f1-5059-43d0-8a22-001bcf2ce19f", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ "for i in range(100):\n", " egraph.simplify(my_special_app(Value(i)), 10)" ] }, { "cell_type": "markdown", "id": "06d04938-f7db-4094-a249-e778d199c3db", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- Too slow in inner loop\n", "- Is there a way we could optimize it\n" ] }, { "cell_type": "markdown", "id": "8ba13f96-2333-43fd-a467-c18cf0daa9e4", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "#### 4. Someone else writes a library for delayed execution\n" ] }, { "cell_type": "code", "execution_count": 39, "id": "17e9ad75-f829-4a0c-bf8f-e9047cd0e177", "metadata": { "editable": true, "scrolled": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [ { "data": { "text/plain": [ "Ellipsis" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "py_mod = Module([ndarray_mod])\n", "\n", "\n", "@py_mod.function\n", "def py_value(s: StringLike) -> Value: ..." ] }, { "cell_type": "markdown", "id": "51cf4880-4576-40a7-8648-491218534d8f", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- While this is happening, someone else, based on the original module, wrote a different execution semantics\n", "- Builds up expression string instead of trying to evaluate eagerly\n" ] }, { "cell_type": "code", "execution_count": null, "id": "5ce8398b-ffac-4bc9-bb53-52c039f35093", "metadata": { "editable": true, "slideshow": { "slide_type": "skip" }, "tags": [] }, "outputs": [], "source": [ "@py_mod.register\n", "def _py_value(l: String, r: String):\n", " yield rewrite(py_value(l) + py_value(r)).to(py_value(join(l, \" + \", r)))\n", " yield rewrite(py_value(l) * py_value(r)).to(py_value(join(l, \" * \", r)))\n", "\n", "\n", "@py_mod.function\n", "def py_values(s: StringLike) -> Values: ...\n", "\n", "\n", "@py_mod.register\n", "def _py_values(l: String, r: String):\n", " yield rewrite(py_values(l)[py_value(r)]).to(py_value(join(l, \"[\", r, \"]\")))\n", " yield rewrite(py_values(l).length()).to(py_value(join(\"len(\", l, \")\")))\n", " yield rewrite(py_values(l).concat(py_values(r))).to(py_values(join(l, \" + \", r)))\n", "\n", "\n", "@py_mod.function\n", "def py_ndarray(s: StringLike) -> NDArray: ...\n", "\n", "\n", "@py_mod.register\n", "def _py_ndarray(l: String, r: String):\n", " yield rewrite(py_ndarray(l)[py_values(r)]).to(py_value(join(l, \"[\", r, \"]\")))\n", " yield rewrite(py_ndarray(l).shape()).to(py_values(join(l, \".shape\")))\n", " yield rewrite(arange(py_value(l))).to(py_ndarray(join(\"np.arange(\", l, \")\")))" ] }, { "cell_type": "markdown", "id": "85e7ceba-65f2-4766-8673-2d4dfa5bab96", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "#### 5. I can use it jit compile my application!\n" ] }, { "cell_type": "code", "execution_count": 41, "id": "96bb493e-74a1-41a1-911e-a67ac31d92e5", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "outputs": [ { "data": { "text/plain": [ "py_value(\"x * x\")" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "egraph = EGraph([cross_mod, py_mod])\n", "egraph.simplify(my_special_app(py_value(\"x\")), 10)" ] }, { "cell_type": "markdown", "id": "5e9b8c74-42df-409c-ac74-66c605e46035", "metadata": { "editable": true, "slideshow": { "slide_type": "notes" }, "tags": [] }, "source": [ "- I pull in third party library\n", "- Add it to my e-graph\n", "- Now I can compile lazily\n", "- py_mod never needed to know about cross product, works with it\n" ] }, { "cell_type": "markdown", "id": "b5abc145-33bf-4093-ae7d-5dd4a60bc6ae", "metadata": { "editable": true, "slideshow": { "slide_type": "skip" }, "tags": [] }, "source": [ "... and add support for jit compilation for the other library I am using, without changing either library:\n" ] }, { "cell_type": "code", "execution_count": 42, "id": "14cec5ba-b96e-46ef-853a-ddbe4ccfb37f", "metadata": { "collapsed": true, "editable": true, "jupyter": { "outputs_hidden": true }, "slideshow": { "slide_type": "skip" }, "tags": [] }, "outputs": [ { "ename": "KeyError", "evalue": "\"Callable ref FunctionRef(name='py_ndarray') not found\"", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[42], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;129;43m@egraph\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mregister\u001b[49m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;43;01mdef\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;21;43m_\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43ml\u001b[49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mString\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mr\u001b[49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mString\u001b[49m\u001b[43m)\u001b[49m\u001b[43m:\u001b[49m\n\u001b[1;32m 3\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01myield\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mrewrite\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcross\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpy_ndarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43ml\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpy_ndarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mr\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpy_ndarray\u001b[49m\u001b[43m(\u001b[49m\u001b[43mjoin\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mnp.multiply.outer(\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43ml\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m, \u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mr\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m)\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/egraph.py:507\u001b[0m, in \u001b[0;36m_BaseModule.register\u001b[0;34m(self, command_or_generator, *commands)\u001b[0m\n\u001b[1;32m 505\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 506\u001b[0m commands \u001b[38;5;241m=\u001b[39m (cast(CommandLike, command_or_generator), \u001b[38;5;241m*\u001b[39mcommands)\n\u001b[0;32m--> 507\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_process_commands\u001b[49m\u001b[43m(\u001b[49m\u001b[43m_command_like\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcommand\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_to_egg_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mcommand\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mcommands\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/egraph.py:634\u001b[0m, in \u001b[0;36mEGraph._process_commands\u001b[0;34m(self, commands)\u001b[0m\n\u001b[1;32m 633\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_process_commands\u001b[39m(\u001b[38;5;28mself\u001b[39m, commands: Iterable[bindings\u001b[38;5;241m.\u001b[39m_Command]) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 634\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_egraph\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_program\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mcommands\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/egraph.py:507\u001b[0m, in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 505\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 506\u001b[0m commands \u001b[38;5;241m=\u001b[39m (cast(CommandLike, command_or_generator), \u001b[38;5;241m*\u001b[39mcommands)\n\u001b[0;32m--> 507\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_process_commands(\u001b[43m_command_like\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcommand\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_to_egg_command\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mfor\u001b[39;00m command \u001b[38;5;129;01min\u001b[39;00m commands)\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/egraph.py:907\u001b[0m, in \u001b[0;36mRewrite._to_egg_command\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 906\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_to_egg_command\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m bindings\u001b[38;5;241m.\u001b[39m_Command:\n\u001b[0;32m--> 907\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m bindings\u001b[38;5;241m.\u001b[39mRewriteCommand(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_ruleset, \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_to_egg_rewrite\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m)\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/egraph.py:911\u001b[0m, in \u001b[0;36mRewrite._to_egg_rewrite\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 909\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_to_egg_rewrite\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m bindings\u001b[38;5;241m.\u001b[39mRewrite:\n\u001b[1;32m 910\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m bindings\u001b[38;5;241m.\u001b[39mRewrite(\n\u001b[0;32m--> 911\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_lhs\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__to_egg__\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 912\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_rhs\u001b[38;5;241m.\u001b[39m__to_egg__(),\n\u001b[1;32m 913\u001b[0m [c\u001b[38;5;241m.\u001b[39m_to_egg_fact() \u001b[38;5;28;01mfor\u001b[39;00m c \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_conditions],\n\u001b[1;32m 914\u001b[0m )\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/runtime.py:370\u001b[0m, in \u001b[0;36mRuntimeExpr.__to_egg__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 369\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__to_egg__\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m bindings\u001b[38;5;241m.\u001b[39m_Expr:\n\u001b[0;32m--> 370\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__egg_typed_expr__\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexpr\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_egg\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__egg_decls__\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/declarations.py:582\u001b[0m, in \u001b[0;36mCallDecl.to_egg\u001b[0;34m(self, mod_decls)\u001b[0m\n\u001b[1;32m 580\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Convert a Call to an egg Call.\"\"\"\u001b[39;00m\n\u001b[1;32m 581\u001b[0m egg_fn \u001b[38;5;241m=\u001b[39m mod_decls\u001b[38;5;241m.\u001b[39mget_egg_fn(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcallable)\n\u001b[0;32m--> 582\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m bindings\u001b[38;5;241m.\u001b[39mCall(egg_fn, [a\u001b[38;5;241m.\u001b[39mto_egg(mod_decls) \u001b[38;5;28;01mfor\u001b[39;00m a \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39margs])\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/declarations.py:582\u001b[0m, in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 580\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Convert a Call to an egg Call.\"\"\"\u001b[39;00m\n\u001b[1;32m 581\u001b[0m egg_fn \u001b[38;5;241m=\u001b[39m mod_decls\u001b[38;5;241m.\u001b[39mget_egg_fn(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcallable)\n\u001b[0;32m--> 582\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m bindings\u001b[38;5;241m.\u001b[39mCall(egg_fn, [\u001b[43ma\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_egg\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmod_decls\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mfor\u001b[39;00m a \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39margs])\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/declarations.py:681\u001b[0m, in \u001b[0;36mTypedExprDecl.to_egg\u001b[0;34m(self, decls)\u001b[0m\n\u001b[1;32m 680\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mto_egg\u001b[39m(\u001b[38;5;28mself\u001b[39m, decls: ModuleDeclarations) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m bindings\u001b[38;5;241m.\u001b[39m_Expr:\n\u001b[0;32m--> 681\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexpr\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_egg\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdecls\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/declarations.py:581\u001b[0m, in \u001b[0;36mCallDecl.to_egg\u001b[0;34m(self, mod_decls)\u001b[0m\n\u001b[1;32m 579\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mto_egg\u001b[39m(\u001b[38;5;28mself\u001b[39m, mod_decls: ModuleDeclarations) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m bindings\u001b[38;5;241m.\u001b[39mCall:\n\u001b[1;32m 580\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Convert a Call to an egg Call.\"\"\"\u001b[39;00m\n\u001b[0;32m--> 581\u001b[0m egg_fn \u001b[38;5;241m=\u001b[39m \u001b[43mmod_decls\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_egg_fn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcallable\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 582\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m bindings\u001b[38;5;241m.\u001b[39mCall(egg_fn, [a\u001b[38;5;241m.\u001b[39mto_egg(mod_decls) \u001b[38;5;28;01mfor\u001b[39;00m a \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39margs])\n", "File \u001b[0;32m~/p/egg-smol-python/python/egglog/declarations.py:205\u001b[0m, in \u001b[0;36mModuleDeclarations.get_egg_fn\u001b[0;34m(self, ref)\u001b[0m\n\u001b[1;32m 203\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m:\n\u001b[1;32m 204\u001b[0m \u001b[38;5;28;01mpass\u001b[39;00m\n\u001b[0;32m--> 205\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCallable ref \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mref\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m not found\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", "\u001b[0;31mKeyError\u001b[0m: \"Callable ref FunctionRef(name='py_ndarray') not found\"" ] } ], "source": [ "@egraph.register\n", "def _(l: String, r: String):\n", " yield rewrite(cross(py_ndarray(l), py_ndarray(r))).to(py_ndarray(join(\"np.multiply.outer(\", l, \", \", r, \")\")))" ] }, { "cell_type": "code", "execution_count": null, "id": "10190128-8d45-4722-8977-4855a0e44be9", "metadata": { "editable": true, "slideshow": { "slide_type": "skip" }, "tags": [] }, "outputs": [], "source": [ "egraph.run(20)\n", "egraph.graphviz().render(outfile=\"big_graph.svg\", format=\"svg\")" ] }, { "cell_type": "markdown", "id": "193b6cf7-01b1-4446-8664-04d622fb0070", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "#### Takeaways...\n", "\n", "_...from this totally realistic example._\n", "\n", "- Declerative nature of `egglog` could facilitate decentralized library collaboration and experimentation.\n", " - Focus on types over values for library authors encourages interoperability.\n", "- Pushing power down, empowering users and library authors\n", "- Could allow greater collaboration between PL community and data science library community in Python\n" ] }, { "cell_type": "markdown", "id": "8ff417fb-cad6-491d-914d-bc8d8cb6880e", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Arrays in the \"Real World\"\n", "\n", "What would it take to make this example work with `egglog`?\n" ] }, { "cell_type": "code", "execution_count": 43, "id": "e0746462-4f02-4119-a28f-dc10e1f9e124", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [ { "data": { "text/plain": [ "array([[ 8.06179978, -0.30042062],\n", " [ 7.12868772, 0.78666043],\n", " [ 7.48982797, 0.26538449],\n", " [ 6.81320057, 0.67063107],\n", " [ 8.13230933, -0.51446253]])" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from sklearn import config_context, datasets\n", "from sklearn.discriminant_analysis import LinearDiscriminantAnalysis\n", "\n", "iris = datasets.load_iris()\n", "\n", "X = iris.data\n", "y = iris.target\n", "\n", "\n", "def fit(X, y):\n", " with config_context(array_api_dispatch=True):\n", " lda = LinearDiscriminantAnalysis(n_components=2)\n", " return lda.fit(X, y).transform(X)\n", "\n", "\n", "fit(X, y)[:5]" ] }, { "cell_type": "markdown", "id": "de801623-8f64-450e-b6bf-4e53e2bdcbe6", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "Could we execute this symbolically?\n", "\n", "```python\n", "@egraph.class_\n", "class NDArray(Expr):\n", " @classmethod\n", " def var(cls, name: StringLike) -> NDArray:\n", " ...\n", "\n", " ...\n", "X_arr = NDArray.var(\"X\")\n", "y_arr = NDArray.var(\"y\")\n", "fit(X_arr, y_arr)\n", "```\n", "\n", "Started working on this yesterday...\n" ] }, { "cell_type": "markdown", "id": "20078da0-a583-414a-853c-0a8a410ce5ff", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "Provide egglog with metadata at least about the types, to get through sklearn's sanity checks (which need to be executed eagerly):\n", "\n", "```python\n", "egraph.register(\n", " rewrite(X_arr.dtype).to(convert(X.dtype, DType)),\n", " rewrite(y_arr.dtype).to(convert(y.dtype, DType)),\n", " rewrite(isfinite(sum(X_arr)).bool()).to(TRUE),\n", " rewrite(isfinite(sum(y_arr)).bool()).to(TRUE),\n", " rewrite(X_arr.shape).to(convert(X.shape, TupleInt)),\n", " rewrite(y_arr.shape).to(convert(y.shape, TupleInt)),\n", " rewrite(X_arr.size).to(Int(X.size)),\n", " rewrite(y_arr.size).to(Int(y.size)),\n", " rewrite(unique_values(y_arr).shape).to(TupleInt(Int(3)))\n", ")\n", "```\n" ] }, { "cell_type": "markdown", "id": "85112e88-b0e7-4cb3-b3fd-7365fb95f16f", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "Define all the required Array API functions:\n", "\n", "```python\n", "@egraph.function\n", "def reshape(x: NDArray, shape: TupleInt, copy: OptionalBool = OptionalBool.none) -> NDArray:\n", " ...\n", "```\n" ] }, { "cell_type": "markdown", "id": "4d36583e-69b0-4698-9792-99799d261782", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "```python\n", "@egraph.register\n", "def _reshape(x: NDArray, y: NDArray, shape: TupleInt, copy: OptionalBool, i: Int, s: String):\n", " return [\n", " # dtype of result is same as input\n", " rewrite(\n", " reshape(x, shape, copy).dtype\n", " ).to(x.dtype),\n", " # dimensions of output are the same as length of shape\n", " rewrite(\n", " reshape(x, shape, copy).shape.length()\n", " ).to(shape.length()),\n", " # Shape of single dimensions reshape is the # elements\n", " rewrite(\n", " reshape(x, TupleInt(Int(-1)), copy).shape\n", " ).to(TupleInt(x.size)),\n", " # Reshaping one dimension no-op\n", " rule(\n", " eq(y).to(reshape(x, TupleInt(Int(-1)), copy)),\n", " eq(x.shape).to(TupleInt(i)),\n", " ).then(\n", " union(x).with_(y)\n", " )\n", " ]\n", "```\n" ] }, { "cell_type": "markdown", "id": "bc1cf64c-f7bf-4ebb-ae55-1b74ea6d795e", "metadata": { "editable": true, "slideshow": { "slide_type": "subslide" }, "tags": [] }, "source": [ "Can see some examples of rewrites executing during sklearns checking:\n", "\n", "```python\n", "asarray(reshape(asarray(NDArray.var(\"y\")), (TupleInt(Int(-1)) + TupleInt.EMPTY))).shape[Int(0)] == asarray(NDArray.var(\"X\")).shape[Int(0)]\n", " -> NDArray.var(\"y\").size == NDArray.var(\"X\").shape[Int(0)]\n", " -> TRUE\n", "\n", "asarray(asarray(reshape(asarray(NDArray.var(\"y\")), (TupleInt(Int(-1)) + TupleInt.EMPTY)))).ndim == Int(2)\n", " -> FALSE\n", "```\n" ] }, { "cell_type": "markdown", "id": "ddf19e72-5204-41f8-860e-cf45dfc0fc20", "metadata": { "editable": true, "slideshow": { "slide_type": "fragment" }, "tags": [] }, "source": [ "That's as far as I got!\n" ] }, { "cell_type": "markdown", "id": "2b67e0b8-3c8d-45a5-a041-4293da7aed9e", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ "## Conclusion\n", "\n", "- e-graphs are a data structure we can use to build term rewriting systems\n", "- `egglog` is a language, and Python library, for building e-graphs\n", "- Looking forward to seeing how it might be used in PyData ecosystem\n", "\n", "```bash\n", "pip install egglog\n", "```\n", "\n", "Welcome new contributations, experiments, and conversations...\n", "\n", "_Come say hello at [github.com/egraphs-good/egglog-python](https://github.com/egraphs-good/egglog-python) ad [egraphs.zulipchat.com](https://egraphs.zulipchat.com/)!_\n" ] }, { "cell_type": "code", "execution_count": null, "id": "8a7fea36-c3f8-4fc2-970b-98ad2f439387", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "egglog-python", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.12" }, "mystnb": { "execution_mode": "off" } }, "nbformat": 4, "nbformat_minor": 5 }