Coverage for /opt/cloud/slavespace/usr1/096471637100f3de0fcfc01072822a80/dttest/api/python/ge/ge/passes/base.py: 94%
64 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-04 11:36 +0800
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-04 11:36 +0800
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# -----------------------------------------------------------------------------------------------------------
4# Copyright (c) 2026 Huawei Technologies Co., Ltd.
5# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
6# CANN Open Software License Agreement Version 2.0 (the "License").
7# Please refer to the License for details. You may not use this file except in compliance with the License.
8# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
9# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
10# See LICENSE in the root of the software repository for the full text of the License.
11# -----------------------------------------------------------------------------------------------------------
13"""Base definitions for Python GE passes."""
15from __future__ import annotations
17from enum import Enum
18from typing import TYPE_CHECKING, Iterable, List, Optional, Union
20from ._native import ( # noqa: F401
21 MatchResult,
22 PassContext,
23 PatternMatcherConfig,
24 PatternMatcherConfigBuilder,
25 SubgraphBoundary,
26 SubgraphInput,
27 SubgraphOutput,
28 SubgraphRewriter,
29)
30from ._native import infer_shape as _infer_shape
32if TYPE_CHECKING:
33 from ge.graph.graph import Graph
34 from ge.graph.node import Node
36 from .pattern import Pattern
39PatternOrGraph = Union["Pattern", "Graph"]
40StatusLike = Optional[Union[bool, int]]
43def infer_shape(
44 replacement: "Graph", source: Union[MatchResult, "Node", SubgraphBoundary]
45) -> None:
46 """Infer shape, data type, and format for a replacement graph from a matched source."""
47 from ge.graph import Graph, Node
49 if not isinstance(replacement, Graph):
50 raise TypeError("replacement must be a ge.graph.Graph")
51 if not isinstance(source, (MatchResult, Node, SubgraphBoundary)):
52 raise TypeError("source must be MatchResult, Node, or SubgraphBoundary")
53 if not replacement.get_all_nodes():
54 raise RuntimeError("replacement graph is empty")
55 _infer_shape(replacement, source)
58class PassStage(str, Enum):
59 """Python-facing pass stage names."""
61 BEFORE_INFER_SHAPE = "BeforeInferShape"
62 AFTER_INFER_SHAPE = "AfterInferShape"
63 AFTER_BUILTIN_FUSION_PASS = "AfterBuiltinFusionPass"
64 AFTER_ORIGIN_GRAPH_OPTIMIZE = "AfterOriginGraphOptimize"
67class FusionBasePass:
68 """Python FusionBasePass contract."""
70 def run(self, graph: Graph, context: PassContext) -> StatusLike:
71 raise NotImplementedError("FusionBasePass.run must be implemented")
74class PatternFusionPass(FusionBasePass):
75 """Python PatternFusionPass contract.
77 The execution engine calls ``patterns()``, ``meet_requirements()``, and
78 ``replacement()`` — **not** ``run()``. Overriding ``run()`` in a
79 ``PatternFusionPass`` subclass has no effect; implement the three hook
80 methods above instead.
82 Subclasses can use either the legacy graph-building hooks:
83 - ``patterns(self) -> Iterable[Pattern | Graph]``
84 - ``meet_requirements(self, match_result) -> bool``
85 - ``replacement(self, match_result) -> Graph``
86 - the same hooks may append ``context: PassContext``
88 or expression-style pattern methods:
89 - ``@pattern def name(self, inputs) -> TensorHolder | list[TensorHolder] | tuple[TensorHolder, ...]``
90 - ``replacement(self, inputs) -> TensorHolder | list[TensorHolder] | tuple[TensorHolder, ...] | Graph``
91 - ``replacement(self, inputs, match_result)`` when match details are needed
92 - ``replacement(self, inputs, context)`` or ``replacement(self, inputs, match_result, context)``
94 In a ``@pattern`` method, a list/tuple means multiple outputs of one
95 pattern, not multiple patterns. Declare several ``@pattern`` methods for
96 a multiple-pattern pass. Expression-style patterns automatically capture
97 accessed inputs in input-index order, then returned outputs in return order.
98 """
100 def __init__(self, matcher_config: Optional[PatternMatcherConfig] = None) -> None:
101 self._matcher_config = matcher_config
103 def __init_subclass__(cls, **kwargs) -> None:
104 super().__init_subclass__(**kwargs)
105 if "run" in cls.__dict__:
106 raise TypeError(
107 f"{cls.__name__} overrides run(), which is never invoked "
108 f"by the PatternFusionPass execution path. "
109 f"Implement patterns()/replacement() instead."
110 )
111 from .pattern import (
112 _adapt_context_hook,
113 _adapt_decorated_pattern_methods,
114 _adapt_replacement_hook,
115 _has_decorated_pattern_methods,
116 )
118 if _has_decorated_pattern_methods(cls):
119 if "patterns" in cls.__dict__:
120 raise TypeError(
121 f"{cls.__name__} cannot combine @pattern methods with patterns(). "
122 f"Use one style for declaring patterns."
123 )
124 cls.patterns = _adapt_decorated_pattern_methods(cls)
125 if "meet_requirements" in cls.__dict__:
126 cls.meet_requirements = _adapt_context_hook(
127 cls.__dict__["meet_requirements"],
128 "meet_requirements",
129 "match_result",
130 )
131 if "replacement" in cls.__dict__:
132 cls.replacement = _adapt_replacement_hook(cls.__dict__["replacement"])
134 @property
135 def matcher_config(self) -> Optional[PatternMatcherConfig]:
136 return self._matcher_config
138 def patterns(self) -> Iterable[PatternOrGraph]:
139 raise NotImplementedError("PatternFusionPass.patterns must be implemented")
141 def meet_requirements(
142 self, match_result: MatchResult, context: Optional[PassContext] = None
143 ) -> bool:
144 return True
146 def replacement(
147 self, match_result: MatchResult, context: Optional[PassContext] = None
148 ) -> "Graph":
149 raise NotImplementedError("PatternFusionPass.replacement must be implemented")
152class DecomposePass(FusionBasePass):
153 """Python DecomposePass contract.
155 The execution engine calls ``meet_requirements()`` and ``replacement()``
156 for matched nodes — **not** ``run()``. Overriding ``run()`` in a
157 ``DecomposePass`` subclass has no effect; implement the two hook methods
158 above instead.
159 """
161 op_types: Optional[List[str]] = None
163 def __init_subclass__(cls, **kwargs) -> None:
164 super().__init_subclass__(**kwargs)
165 if "run" in cls.__dict__:
166 raise TypeError(
167 f"{cls.__name__} overrides run(), which is never invoked "
168 f"by the DecomposePass execution path. "
169 f"Implement meet_requirements()/replacement() instead."
170 )
171 from .pattern import _adapt_context_hook
173 if "meet_requirements" in cls.__dict__:
174 cls.meet_requirements = _adapt_context_hook(
175 cls.__dict__["meet_requirements"], "meet_requirements", "node"
176 )
177 if "replacement" in cls.__dict__:
178 cls.replacement = _adapt_context_hook(
179 cls.__dict__["replacement"], "replacement", "node"
180 )
182 def meet_requirements(
183 self, node: "Node", context: Optional[PassContext] = None
184 ) -> bool:
185 return True
187 def replacement(
188 self, node: "Node", context: Optional[PassContext] = None
189 ) -> "Graph":
190 raise NotImplementedError("DecomposePass.replacement must be implemented")