Add apyds-egg support package with E-Graph implementation - #146
Conversation
Co-authored-by: hzhangxyz <11623447+hzhangxyz@users.noreply.github.com>
| @@ -0,0 +1,25 @@ | |||
| __pycache__/ | |||
There was a problem hiding this comment.
这个文件是不需要的, 会被repo root的ignore给忽略掉.
There was a problem hiding this comment.
Removed in b04b828. The repo root .gitignore handles the necessary patterns.
| @@ -0,0 +1,4 @@ | |||
| import setuptools | |||
There was a problem hiding this comment.
Removed in b04b828. The package builds correctly with just pyproject.toml using the setuptools build backend.
Co-authored-by: hzhangxyz <11623447+hzhangxyz@users.noreply.github.com>
hzhangxyz
left a comment
There was a problem hiding this comment.
- README.md 先删掉, 不要在此pr中实现
- init.py中我做了一些修改, 删除了一些意外的判断, 这个不需要判断, 类型标记写好, 然后假设用户只会这样输入, 我尽量修改了, 如果有漏的, 你也改一下
- 用from future import annotation 那个, 不要写
"ENode"这样的字符串类型 - init.py 中我做了一些修改, 所以tests有些过不了了, 你修修删删.
…ests Co-authored-by: hzhangxyz <11623447+hzhangxyz@users.noreply.github.com>
All addressed in 9acd306:
|
| def test_egraph_congruence(): | ||
| eg = EGraph() | ||
|
|
||
| x = eg.add(apyds.Term("x")) |
|
|
||
| a = eg.add(apyds.Term("a")) | ||
| b = eg.add(apyds.Term("b")) | ||
| c = eg.add(apyds.Term("c")) |
| def test_egraph_complex_example(): | ||
| eg = EGraph() | ||
|
|
||
| x = eg.add(apyds.Term("x")) |
| def test_egraph_associativity_example(): | ||
| eg = EGraph() | ||
|
|
||
| x = eg.add(apyds.Term("x")) |
| eg = EGraph() | ||
|
|
||
| x = eg.add(apyds.Term("x")) | ||
| y = eg.add(apyds.Term("y")) |
|
|
||
| x = eg.add(apyds.Term("x")) | ||
| y = eg.add(apyds.Term("y")) | ||
| z = eg.add(apyds.Term("z")) |
| def test_egraph_hashcons(): | ||
| eg = EGraph() | ||
|
|
||
| a = eg.add(apyds.Term("a")) |
| eg = EGraph() | ||
|
|
||
| a = eg.add(apyds.Term("a")) | ||
| b = eg.add(apyds.Term("b")) |
There was a problem hiding this comment.
Pull request overview
This PR adds the apyds-egg support package, implementing an E-Graph (Equality Graph) data structure for representing and manipulating equivalence classes of terms. The package provides a Python implementation following a structure similar to the existing /bnf package.
Key changes:
- Implementation of core E-Graph components: UnionFind, ENode, and EGraph classes
- Integration with apyds.Term for seamless term handling
- Comprehensive test suite with 24 tests covering basic operations, congruence, and edge cases
Reviewed changes
Copilot reviewed 3 out of 5 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| egg/pyproject.toml | Package configuration with build system, dependencies, and tool settings |
| egg/uv.lock | Dependency lock file with apyds 0.0.10 and dev dependencies |
| egg/apyds_egg/init.py | Core E-Graph implementation with union-find, node canonicalization, and congruence maintenance |
| egg/apyds_egg/py.typed | Type checking marker file for PEP 561 compliance |
| egg/tests/test_egraph.py | Comprehensive test suite covering all E-Graph operations and edge cases |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return eid | ||
|
|
||
| def merge(self, a: EClassId, b: EClassId) -> EClassId: | ||
| """Merge two E-classes and schedule rebuilding.""" |
There was a problem hiding this comment.
The merge method lacks complete documentation. It should document its parameters (what a and b represent), return value (what the returned EClassId represents), and the important side effect that rebuild() must be called after merge operations to maintain congruence.
| """Merge two E-classes and schedule rebuilding.""" | |
| """Merge two E-classes and schedule rebuilding. | |
| Parameters | |
| ---------- | |
| a : EClassId | |
| The ID of the first E-class to merge. | |
| b : EClassId | |
| The ID of the second E-class to merge. | |
| Returns | |
| ------- | |
| EClassId | |
| The canonical E-class ID representing the union of ``a`` and ``b``. | |
| Notes | |
| ----- | |
| This method updates internal parent/class/parent-links structures and | |
| adds the resulting E-class to the worklist for congruence repair. | |
| Call :meth:`rebuild` after performing merges to restore global | |
| congruence in the E-Graph. | |
| """ |
| return eid | ||
|
|
||
| def find(self, eclass: EClassId) -> EClassId: | ||
| """Find the canonical representative of an E-class.""" |
There was a problem hiding this comment.
The find method lacks documentation about its parameter. It should document what eclass represents (an E-class ID to look up) and clarify that it returns the canonical representative after any merge operations.
| """Find the canonical representative of an E-class.""" | |
| """Find the canonical representative of an E-class. | |
| Args: | |
| eclass: The E-class ID to look up. | |
| Returns: | |
| The canonical E-class ID representing ``eclass`` after applying | |
| any union/merge operations. | |
| """ |
| for i in range(len(inner)): | ||
| child_term = inner[i] |
There was a problem hiding this comment.
The loop iterating over List elements using range(len(inner)) could be simplified to iterate directly over the List. Instead of using a range-based loop, consider iterating directly: for child_term in inner. This would be more idiomatic Python and slightly more efficient.
| for i in range(len(inner)): | |
| child_term = inner[i] | |
| for child_term in inner: |
| requires-python = ">=3.11, <3.15" | ||
| authors = [{ name = "Hao Zhang", email = "hzhangxyz@outlook.com" }] | ||
| description = "E-Graph implementation for apyds" | ||
| readme = "README.md" |
There was a problem hiding this comment.
The pyproject.toml references a README.md file that doesn't exist in the egg directory. This will cause package build failures. According to the PR description, the README.md was intentionally removed and will be added in a separate PR, so this reference should also be removed from pyproject.toml.
| readme = "README.md" |
| def test_egraph_congruence(): | ||
| eg = EGraph() | ||
|
|
||
| x = eg.add(apyds.Term("x")) |
There was a problem hiding this comment.
Variable x is not used.
| x = eg.add(apyds.Term("x")) |
| def test_egraph_associativity_example(): | ||
| eg = EGraph() | ||
|
|
||
| x = eg.add(apyds.Term("x")) |
There was a problem hiding this comment.
Variable x is not used.
| x = eg.add(apyds.Term("x")) | ||
| y = eg.add(apyds.Term("y")) | ||
| z = eg.add(apyds.Term("z")) | ||
|
|
There was a problem hiding this comment.
Variable y is not used.
| assert isinstance(x, int) | |
| assert isinstance(y, int) | |
| assert isinstance(z, int) |
| x = eg.add(apyds.Term("x")) | ||
| y = eg.add(apyds.Term("y")) | ||
| z = eg.add(apyds.Term("z")) | ||
|
|
There was a problem hiding this comment.
Variable z is not used.
| assert isinstance(x, int) | |
| assert isinstance(y, int) | |
| assert isinstance(z, int) |
| a = eg.add(apyds.Term("a")) | ||
| b = eg.add(apyds.Term("b")) |
There was a problem hiding this comment.
Variable a is not used.
| a = eg.add(apyds.Term("a")) | |
| b = eg.add(apyds.Term("b")) | |
| eg.add(apyds.Term("a")) | |
| eg.add(apyds.Term("b")) |
| eg = EGraph() | ||
|
|
||
| a = eg.add(apyds.Term("a")) | ||
| b = eg.add(apyds.Term("b")) |
There was a problem hiding this comment.
Variable b is not used.
| b = eg.add(apyds.Term("b")) | |
| eg.add(apyds.Term("b")) |
Implementation Plan for apyds-egg Package
/eggdirectory structure similar to/bnfegg/pyproject.tomlwith proper configurationCreateRemoved - not needed for modern build backendsegg/setup.py(minimal, no ANTLR generation needed)CreateRemoved - will be added in a separate PRegg/README.mdwith package documentationegg/apyds_egg/__init__.pywith core E-Graph implementationUnionFindclassENodeclass (using string op and tuple of EClassId children)EGraphclass with add, merge, rebuild, repair methodsaddmethod to accept apyds.Term as inputfrom __future__ import annotationsfor forward references"ENode"->ENode)egg/tests/test_egraph.pywith comprehensive testsegg/apyds_egg/py.typedmarker fileCreateRemoved - handled by repo root .gitignoreegg/apyds_egg/.gitignoreif neededegg/setup.py(not needed for modern build backends)egg/apyds_egg/.gitignore(repo root handles it)egg/README.md(will be added separately)from __future__ import annotationsto avoid string type hintsOriginal prompt
This section details on the original issue you should resolve
<issue_title>添加一个support package叫做apyds-egg</issue_title>
<issue_description>放在/egg下吧,组织形式参考/bnf下的结构。
不过这个只需要实现python的就可以了,不用js。
item和variable直接那字符串当op,list的op可以用绝对不会出现在item和variable中的“()"。
具体的egg可以参考下面来自gpt的demo:
需要注意,这个demo无论是注释/风格/类型,都不适合我们这个仓库,需要做较大的改动
add的输入应该是一个apyds的Term,apyds的用法从/tests/下的python测试文件中可以了解。</issue_description>
C...
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.