Skip to content

Split pattern.py #2296

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
May 13, 2025
Merged

Split pattern.py #2296

merged 13 commits into from
May 13, 2025

Conversation

gramalingam
Copy link
Collaborator

Splitting pattern.py into multiple files, each more focused:

  • _basics.py
  • _pattern_ir.py: the IR for pattern-graphs
  • _rewrite_rule.py: Rewrite Rules
  • _matcher.py: the pattern-matching algorithm

There is more cleanup to be done in each part, but keeping this PR simple, focused only on the split-up, to avoid any major merge-issues.

Copy link

codecov bot commented May 12, 2025

❌ 3 Tests Failed:

Tests completed Failed Passed Skipped
14698 3 14695 1698
View the top 3 failed test(s) by shortest run time
onnxscript.backend.onnx_export_test.TestOnnxBackEnd::test_export2python_produces_correct_onnx_script_model_0981_test_ai_onnx_ml_tree_ensemble_set_membership
Stack Traces | 0.01s run time
onnxscript/converter.py:460: in _eval_constant_expr
    return eval(cpl, self.globals, locals)  # pylint: disable=eval-used
E   NameError: name 'nan' is not defined

The above exception was the direct cause of the following exception:
..../test_ort_nightly/lib/python3.11.../site-packages/parameterized/parameterized.py:620: in standalone_func
    return func(*(a + p.args), **p.kwargs, **kw)
onnxscript/backend/onnx_export_test.py:271: in test_export2python_produces_correct_onnx_script_model
    functions = extract_functions(backend_test.name, code, self.test_folder)
onnxscript/backend/onnx_export_test.py:137: in extract_functions
    mod = importlib.import_module(import_name)
.../hostedtoolcache/Python/3.11.12.../x64/lib/python3.11/importlib/__init__.py:126: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
<frozen importlib._bootstrap>:1204: in _gcd_import
    ???
<frozen importlib._bootstrap>:1176: in _find_and_load
    ???
<frozen importlib._bootstrap>:1147: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:690: in _load_unlocked
    ???
..../test_ort_nightly/lib/python3.11.../_pytest/assertion/rewrite.py:185: in exec_module
    exec(co, module.__dict__)
tests/onnx_backend_test_code/test_ai_onnx_ml_tree_ensemble_set_membership.py:9: in <module>
    @script()
onnxscript/main.py:94: in transform
    result = script_check(f_ast, opset, env, src, default_opset=default_opset)
onnxscript/main.py:38: in script_check
    return convert.translate_function_def(f)
onnxscript/converter.py:1452: in translate_function_def
    fn_ir = self._translate_function_def_common(stmt)
onnxscript/converter.py:1439: in _translate_function_def_common
    self._translate_stmt(s, index_of_stmt=i)
onnxscript/converter.py:961: in _translate_stmt
    return self._translate_assign_stmt(node)
onnxscript/converter.py:1048: in _translate_assign_stmt
    assign(lhs, rhs)
onnxscript/converter.py:992: in assign
    t = self._translate_expr(rhs, lhs).name
onnxscript/converter.py:546: in _translate_expr
    r = self._translate_call_expr(node)
onnxscript/converter.py:825: in _translate_call_expr
    attrs = [
onnxscript/converter.py:826: in <listcomp>
    self._translate_attr(x, y, callee.op_schema.attributes[x])
onnxscript/converter.py:510: in _translate_attr
    val = self._eval_constant_expr(expr)
onnxscript/converter.py:462: in _eval_constant_expr
    raise NameError(
E   NameError: ERROR: Missing names, globals contains ['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__file__', '__cached__', '__builtins__', '@py_builtins', '@pytest_ar', 'numpy', 'TensorProto', 'make_tensor', 'script', 'external_tensor', 'Opset', 'FLOAT', 'ai_onnx_ml5'], locals [].
E   at: Function 'bck_test_ai_onnx_ml_tree_ensemble_set_membership', line 3
E       Y = ai_onnx_ml5.TreeEnsemble(X, aggregate_function=1, leaf_targetids=[0, 1, 2, 3], leaf_weights=make_tensor("value", 1, dims=[4], vals=[1.0, 10.0, 1000.0, 100.0]), membership_values=make_tensor("value", 1, dims=[8], vals=[1.2000000476837158, 3.700000047683716, 8.0, 9.0, nan, 12.0, 7.0, nan]), n_targets=4, nodes_falseleafs=[1, 0, 1], nodes_falsenodeids=[2, 2, 3], nodes_featureids=[0, 0, 0], nodes_modes=make_tensor("value", 2, dims=[3], vals=[0, 6, 6]), nodes_splits=make_tensor("value", 1, dims=[3], vals=[11.0, 232344.0, nan]), nodes_trueleafs=[0, 1, 1], nodes_truenodeids=[1, 0, 1], post_transform=0, tree_roots=[0])
E                                                                                                                                                                                             ^
onnxscript.backend.onnx_export_test.TestOnnxBackEnd::test_export2python_produces_correct_onnx_script_model_0026_test_ai_onnx_ml_tree_ensemble_set_membership
Stack Traces | 0.021s run time
onnxscript\converter.py:460: in _eval_constant_expr
    return eval(cpl, self.globals, locals)  # pylint: disable=eval-used
E   NameError: name 'nan' is not defined

The above exception was the direct cause of the following exception:
.nox\test_ort_nightly\Lib\site-packages\parameterized\parameterized.py:620: in standalone_func
    return func(*(a + p.args), **p.kwargs, **kw)
onnxscript\backend\onnx_export_test.py:271: in test_export2python_produces_correct_onnx_script_model
    functions = extract_functions(backend_test.name, code, self.test_folder)
onnxscript\backend\onnx_export_test.py:137: in extract_functions
    mod = importlib.import_module(import_name)
C:\hostedtoolcache\windows\Python\3.11.9\x64\Lib\importlib\__init__.py:126: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
<frozen importlib._bootstrap>:1204: in _gcd_import
    ???
<frozen importlib._bootstrap>:1176: in _find_and_load
    ???
<frozen importlib._bootstrap>:1147: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:690: in _load_unlocked
    ???
.nox\test_ort_nightly\Lib\site-packages\_pytest\assertion\rewrite.py:185: in exec_module
    exec(co, module.__dict__)
tests\onnx_backend_test_code\test_ai_onnx_ml_tree_ensemble_set_membership.py:9: in <module>
    @script()
onnxscript\main.py:94: in transform
    result = script_check(f_ast, opset, env, src, default_opset=default_opset)
onnxscript\main.py:38: in script_check
    return convert.translate_function_def(f)
onnxscript\converter.py:1452: in translate_function_def
    fn_ir = self._translate_function_def_common(stmt)
onnxscript\converter.py:1439: in _translate_function_def_common
    self._translate_stmt(s, index_of_stmt=i)
onnxscript\converter.py:961: in _translate_stmt
    return self._translate_assign_stmt(node)
onnxscript\converter.py:1048: in _translate_assign_stmt
    assign(lhs, rhs)
onnxscript\converter.py:992: in assign
    t = self._translate_expr(rhs, lhs).name
onnxscript\converter.py:546: in _translate_expr
    r = self._translate_call_expr(node)
onnxscript\converter.py:825: in _translate_call_expr
    attrs = [
onnxscript\converter.py:826: in <listcomp>
    self._translate_attr(x, y, callee.op_schema.attributes[x])
onnxscript\converter.py:510: in _translate_attr
    val = self._eval_constant_expr(expr)
onnxscript\converter.py:462: in _eval_constant_expr
    raise NameError(
E   NameError: ERROR: Missing names, globals contains ['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__file__', '__cached__', '__builtins__', '@py_builtins', '@pytest_ar', 'numpy', 'TensorProto', 'make_tensor', 'script', 'external_tensor', 'Opset', 'FLOAT', 'ai_onnx_ml5'], locals [].
E   at: Function 'bck_test_ai_onnx_ml_tree_ensemble_set_membership', line 3
E       Y = ai_onnx_ml5.TreeEnsemble(X, aggregate_function=1, leaf_targetids=[0, 1, 2, 3], leaf_weights=make_tensor("value", 1, dims=[4], vals=[1.0, 10.0, 1000.0, 100.0]), membership_values=make_tensor("value", 1, dims=[8], vals=[1.2000000476837158, 3.700000047683716, 8.0, 9.0, nan, 12.0, 7.0, nan]), n_targets=4, nodes_falseleafs=[1, 0, 1], nodes_falsenodeids=[2, 2, 3], nodes_featureids=[0, 0, 0], nodes_modes=make_tensor("value", 2, dims=[3], vals=[0, 6, 6]), nodes_splits=make_tensor("value", 1, dims=[3], vals=[11.0, 232344.0, nan]), nodes_trueleafs=[0, 1, 1], nodes_truenodeids=[1, 0, 1], post_transform=0, tree_roots=[0])
E                                                                                                                                                                                             ^
onnxscript.backend.onnx_export_test.TestOnnxBackEnd::test_export2python_produces_correct_onnx_script_model_0125_test_ai_onnx_ml_tree_ensemble_set_membership
Stack Traces | 0.022s run time
onnxscript/converter.py:460: in _eval_constant_expr
    return eval(cpl, self.globals, locals)  # pylint: disable=eval-used
E   NameError: name 'nan' is not defined

The above exception was the direct cause of the following exception:
..../test_ort_nightly/lib/python3.11.../site-packages/parameterized/parameterized.py:620: in standalone_func
    return func(*(a + p.args), **p.kwargs, **kw)
onnxscript/backend/onnx_export_test.py:271: in test_export2python_produces_correct_onnx_script_model
    functions = extract_functions(backend_test.name, code, self.test_folder)
onnxscript/backend/onnx_export_test.py:137: in extract_functions
    mod = importlib.import_module(import_name)
.../Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/importlib/__init__.py:126: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
<frozen importlib._bootstrap>:1204: in _gcd_import
    ???
<frozen importlib._bootstrap>:1176: in _find_and_load
    ???
<frozen importlib._bootstrap>:1147: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:690: in _load_unlocked
    ???
..../test_ort_nightly/lib/python3.11.../_pytest/assertion/rewrite.py:185: in exec_module
    exec(co, module.__dict__)
tests/onnx_backend_test_code/test_ai_onnx_ml_tree_ensemble_set_membership.py:9: in <module>
    @script()
onnxscript/main.py:94: in transform
    result = script_check(f_ast, opset, env, src, default_opset=default_opset)
onnxscript/main.py:38: in script_check
    return convert.translate_function_def(f)
onnxscript/converter.py:1452: in translate_function_def
    fn_ir = self._translate_function_def_common(stmt)
onnxscript/converter.py:1439: in _translate_function_def_common
    self._translate_stmt(s, index_of_stmt=i)
onnxscript/converter.py:961: in _translate_stmt
    return self._translate_assign_stmt(node)
onnxscript/converter.py:1048: in _translate_assign_stmt
    assign(lhs, rhs)
onnxscript/converter.py:992: in assign
    t = self._translate_expr(rhs, lhs).name
onnxscript/converter.py:546: in _translate_expr
    r = self._translate_call_expr(node)
onnxscript/converter.py:825: in _translate_call_expr
    attrs = [
onnxscript/converter.py:826: in <listcomp>
    self._translate_attr(x, y, callee.op_schema.attributes[x])
onnxscript/converter.py:510: in _translate_attr
    val = self._eval_constant_expr(expr)
onnxscript/converter.py:462: in _eval_constant_expr
    raise NameError(
E   NameError: ERROR: Missing names, globals contains ['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__file__', '__cached__', '__builtins__', '@py_builtins', '@pytest_ar', 'numpy', 'TensorProto', 'make_tensor', 'script', 'external_tensor', 'Opset', 'FLOAT', 'ai_onnx_ml5'], locals [].
E   at: Function 'bck_test_ai_onnx_ml_tree_ensemble_set_membership', line 3
E       Y = ai_onnx_ml5.TreeEnsemble(X, aggregate_function=1, leaf_targetids=[0, 1, 2, 3], leaf_weights=make_tensor("value", 1, dims=[4], vals=[1.0, 10.0, 1000.0, 100.0]), membership_values=make_tensor("value", 1, dims=[8], vals=[1.2000000476837158, 3.700000047683716, 8.0, 9.0, nan, 12.0, 7.0, nan]), n_targets=4, nodes_falseleafs=[1, 0, 1], nodes_falsenodeids=[2, 2, 3], nodes_featureids=[0, 0, 0], nodes_modes=make_tensor("value", 2, dims=[3], vals=[0, 6, 6]), nodes_splits=make_tensor("value", 1, dims=[3], vals=[11.0, 232344.0, nan]), nodes_trueleafs=[0, 1, 1], nodes_truenodeids=[1, 0, 1], post_transform=0, tree_roots=[0])
E                                                                                                                                                                                             ^

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Copy link
Contributor

@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

@gramalingam gramalingam enabled auto-merge (squash) May 13, 2025 17:52
node: ir.Node,
*,
verbose: int | None = None,
tracer: _basics.MatchingTracer | None = None,

Check failure

Code scanning / CodeQL

Module-level cyclic import Error

'MatchingTracer' may not be defined if module
onnxscript.rewriter._basics
is imported before module
onnxscript.rewriter._rewrite_rule
, as the
definition
of MatchingTracer occurs after the cyclic
import
of onnxscript.rewriter._rewrite_rule.

Copilot Autofix

AI about 2 months ago

To fix the cyclic import issue, we need to break the dependency loop between _rewrite_rule and _basics. One way to achieve this is by deferring the import of _basics.MatchingTracer to the point where it is actually needed, rather than importing it at the module level. This can be done by moving the import statement for _basics.MatchingTracer inside the try_rewrite method, where it is used. This approach ensures that _basics is fully initialized before MatchingTracer is accessed, thereby resolving the cyclic import issue.


Suggested changeset 1
onnxscript/rewriter/_rewrite_rule.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/onnxscript/rewriter/_rewrite_rule.py b/onnxscript/rewriter/_rewrite_rule.py
--- a/onnxscript/rewriter/_rewrite_rule.py
+++ b/onnxscript/rewriter/_rewrite_rule.py
@@ -161,3 +161,3 @@
         verbose: int | None = None,
-        tracer: _basics.MatchingTracer | None = None,
+        tracer: "MatchingTracer | None" = None,  # Deferred import to avoid cyclic dependency
     ) -> ReplacementSubgraph | None:
@@ -216,3 +216,4 @@
         if tracer:
-            tracer.log(self, graph_or_function, node, match, _basics.MatchStatus.NO_MATCH)
+            from onnxscript.rewriter._basics import MatchingTracer  # Deferred import
+            tracer.log(self, graph_or_function, node, match, MatchingTracer.MatchStatus.NO_MATCH)
         return None
EOF
@@ -161,3 +161,3 @@
verbose: int | None = None,
tracer: _basics.MatchingTracer | None = None,
tracer: "MatchingTracer | None" = None, # Deferred import to avoid cyclic dependency
) -> ReplacementSubgraph | None:
@@ -216,3 +216,4 @@
if tracer:
tracer.log(self, graph_or_function, node, match, _basics.MatchStatus.NO_MATCH)
from onnxscript.rewriter._basics import MatchingTracer # Deferred import
tracer.log(self, graph_or_function, node, match, MatchingTracer.MatchStatus.NO_MATCH)
return None
Copilot is powered by AI and may make mistakes. Always verify output.
*,
commute: bool = False,
verbose: int | None = None,
tracer: _basics.MatchingTracer | None = None,

Check failure

Code scanning / CodeQL

Module-level cyclic import Error

'MatchingTracer' may not be defined if module
onnxscript.rewriter._basics
is imported before module
onnxscript.rewriter._rewrite_rule
, as the
definition
of MatchingTracer occurs after the cyclic
import
of onnxscript.rewriter._rewrite_rule.

Copilot Autofix

AI about 2 months ago

To resolve the cyclic import issue, we need to break the dependency loop between _rewrite_rule and _basics. One effective way to do this is to use a local import for MatchingTracer within the method where it is used (try_rewrite). This ensures that MatchingTracer is only imported when the method is called, avoiding the cyclic dependency during module initialization. This approach minimizes changes to the codebase and preserves existing functionality.


Suggested changeset 1
onnxscript/rewriter/_rewrite_rule.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/onnxscript/rewriter/_rewrite_rule.py b/onnxscript/rewriter/_rewrite_rule.py
--- a/onnxscript/rewriter/_rewrite_rule.py
+++ b/onnxscript/rewriter/_rewrite_rule.py
@@ -161,5 +161,6 @@
         verbose: int | None = None,
-        tracer: _basics.MatchingTracer | None = None,
+        tracer: "MatchingTracer" | None = None,
     ) -> ReplacementSubgraph | None:
         """If the node matches the pattern, then replace the node with the replacement pattern."""
+        from onnxscript.rewriter._basics import MatchingTracer
         if verbose and verbose > 2:
EOF
@@ -161,5 +161,6 @@
verbose: int | None = None,
tracer: _basics.MatchingTracer | None = None,
tracer: "MatchingTracer" | None = None,
) -> ReplacementSubgraph | None:
"""If the node matches the pattern, then replace the node with the replacement pattern."""
from onnxscript.rewriter._basics import MatchingTracer
if verbose and verbose > 2:
Copilot is powered by AI and may make mistakes. Always verify output.
graph_or_function: ir.Graph | ir.Function,
*,
verbose: int | None,
tracer: _basics.MatchingTracer | None = None,

Check failure

Code scanning / CodeQL

Module-level cyclic import Error

'MatchingTracer' may not be defined if module
onnxscript.rewriter._basics
is imported before module
onnxscript.rewriter._rewrite_rule
, as the
definition
of MatchingTracer occurs after the cyclic
import
of onnxscript.rewriter._rewrite_rule.

Copilot Autofix

AI about 2 months ago

To fix the cyclic import issue, we need to break the dependency loop between _rewrite_rule and _basics. One way to achieve this is to move the MatchingTracer reference to a local import within the method where it is used (_apply_to_graph_or_function). This ensures that _basics.MatchingTracer is only imported when needed, avoiding the cyclic import at the module level.

Steps to fix:

  1. Remove the module-level import of _basics.MatchingTracer.
  2. Add a local import of _basics.MatchingTracer inside the _apply_to_graph_or_function method, where it is used.

Suggested changeset 1
onnxscript/rewriter/_rewrite_rule.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/onnxscript/rewriter/_rewrite_rule.py b/onnxscript/rewriter/_rewrite_rule.py
--- a/onnxscript/rewriter/_rewrite_rule.py
+++ b/onnxscript/rewriter/_rewrite_rule.py
@@ -16,3 +16,3 @@
 import onnxscript.optimizer
-import onnxscript.rewriter._basics as _basics
+import onnxscript.rewriter._basics as _basics  # Keep the import for other references, but remove `MatchingTracer` usage here.
 import onnxscript.rewriter._matcher as _matcher
@@ -446,3 +446,3 @@
         verbose: int | None,
-        tracer: _basics.MatchingTracer | None = None,
+        tracer: "onnxscript.rewriter._basics.MatchingTracer" | None = None,  # Use a string annotation to avoid early evaluation.
     ) -> int:
@@ -464,2 +464,3 @@
         # And the graph is applied in order.
+        from onnxscript.rewriter._basics import MatchingTracer  # Local import to avoid cyclic dependency.
         for rule in self.rules:
EOF
@@ -16,3 +16,3 @@
import onnxscript.optimizer
import onnxscript.rewriter._basics as _basics
import onnxscript.rewriter._basics as _basics # Keep the import for other references, but remove `MatchingTracer` usage here.
import onnxscript.rewriter._matcher as _matcher
@@ -446,3 +446,3 @@
verbose: int | None,
tracer: _basics.MatchingTracer | None = None,
tracer: "onnxscript.rewriter._basics.MatchingTracer" | None = None, # Use a string annotation to avoid early evaluation.
) -> int:
@@ -464,2 +464,3 @@
# And the graph is applied in order.
from onnxscript.rewriter._basics import MatchingTracer # Local import to avoid cyclic dependency.
for rule in self.rules:
Copilot is powered by AI and may make mistakes. Always verify output.
model: ir.Model,
*,
verbose: int | None = None,
tracer: _basics.MatchingTracer | None = None,

Check failure

Code scanning / CodeQL

Module-level cyclic import Error

'MatchingTracer' may not be defined if module
onnxscript.rewriter._basics
is imported before module
onnxscript.rewriter._rewrite_rule
, as the
definition
of MatchingTracer occurs after the cyclic
import
of onnxscript.rewriter._rewrite_rule.

Copilot Autofix

AI about 2 months ago

To resolve the cyclic import issue, we can break the dependency by deferring the import of MatchingTracer from _basics to the point where it is actually needed. This can be achieved by moving the import inside the apply_to_model method, where _basics.MatchingTracer is used. This ensures that _basics is fully initialized before MatchingTracer is accessed, eliminating the cyclic dependency at the module level.


Suggested changeset 1
onnxscript/rewriter/_rewrite_rule.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/onnxscript/rewriter/_rewrite_rule.py b/onnxscript/rewriter/_rewrite_rule.py
--- a/onnxscript/rewriter/_rewrite_rule.py
+++ b/onnxscript/rewriter/_rewrite_rule.py
@@ -547,3 +547,3 @@
         verbose: int | None = None,
-        tracer: _basics.MatchingTracer | None = None,
+        tracer: "MatchingTracer | None" = None,
     ) -> int:
@@ -560,2 +560,3 @@
         """
+        from onnxscript.rewriter._basics import MatchingTracer
         assert isinstance(model, ir.Model)
EOF
@@ -547,3 +547,3 @@
verbose: int | None = None,
tracer: _basics.MatchingTracer | None = None,
tracer: "MatchingTracer | None" = None,
) -> int:
@@ -560,2 +560,3 @@
"""
from onnxscript.rewriter._basics import MatchingTracer
assert isinstance(model, ir.Model)
Copilot is powered by AI and may make mistakes. Always verify output.
@justinchuby
Copy link
Collaborator

The string types are not needed actually since we import from future already


Example::

class TransposeIdentity(RewriteRuleAsClass):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I realized this should be RewriteRuleClassBase

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right ... this PR auto-merged, will fix it separately.

@gramalingam gramalingam merged commit 88a6f75 into main May 13, 2025
25 of 29 checks passed
@gramalingam gramalingam deleted the rama/refactor branch May 13, 2025 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

Successfully merging this pull request may close these issues.

2 participants