feat: эвристическое отсечение (pruning) в explode_callgraph_branches

Добавлены параметры для pruning:
- priority_threshold: минимальный приоритет для рассмотрения
- min_consumed_types: минимальное количество consumed_types

Pruning применяется в:
- _explode_callgraph_branches_lazy(): отсечение по приоритету и consumed_types
- explode_callgraph_branches(): передача параметров pruning

По умолчанию pruning отключён (priority_threshold=-1e9, min_consumed_types=0)
для обратной совместимости.

Файлы:
- graph_walker.py: параметры pruning в explode и _explode_lazy

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
Qwen Code Assistant
2026-03-28 17:46:31 +00:00
parent f14b07c381
commit 10f9672577

View File

@@ -111,18 +111,36 @@ class GraphWalker:
return head
@classmethod
def explode_callgraph_branches(cls, g: Callgraph, from_types: frozenset[type]) -> list[CallgraphVariant]:
def explode_callgraph_branches(cls, g: Callgraph, from_types: frozenset[type],
priority_threshold: float = -1e9,
min_consumed_types: int = 0) -> list[CallgraphVariant]:
"""
Взрыв графа преобразований с pruning.
Args:
g: Граф преобразований
from_types: Исходные типы
priority_threshold: Минимальный приоритет для рассмотрения (pruning)
min_consumed_types: Минимальное количество consumed_types (pruning)
Returns:
list[CallgraphVariant]: Варианты преобразований
"""
# Кэширование: создаём хэш графа
# Хэш графа = хэш всех вариантов
g_hash = hash(frozenset(g.variants)) if g.variants else 0
cache_key = (g_hash, hash(from_types))
cache_key = (g_hash, hash(from_types), hash(priority_threshold), hash(min_consumed_types))
# Проверяем кэш
if cache_key in cls._explode_cache:
return cls._explode_cache[cache_key]
# Вычисляем лениво через generator
variants = list(cls._explode_callgraph_branches_lazy(g, from_types))
variants = list(cls._explode_callgraph_branches_lazy(
g, from_types,
priority_threshold=priority_threshold,
min_consumed_types=min_consumed_types
))
# Сохраняем в кэш
cls._explode_cache[cache_key] = variants
@@ -130,22 +148,46 @@ class GraphWalker:
return variants
@classmethod
def _explode_callgraph_branches_lazy(cls, g: Callgraph, from_types: frozenset[type]):
def _explode_callgraph_branches_lazy(cls, g: Callgraph, from_types: frozenset[type],
priority_threshold: float = -1e9,
min_consumed_types: int = 0):
"""
Ленивая версия explode_callgraph_branches (generator).
Ленивая версия explode_callgraph_branches (generator) с pruning.
Args:
g: Граф преобразований
from_types: Исходные типы
priority_threshold: Минимальный приоритет для рассмотрения (pruning)
min_consumed_types: Минимальное количество consumed_types (pruning)
Yields:
CallgraphVariant: Варианты преобразований по одному
"""
for variant in g.variants:
if len(variant.subgraphs) == 0:
yield variant
# Pruning: проверяем порог приоритета
variant_priority = variant.injector.priority if isinstance(variant.injector.priority, (int, float)) else 0.0
if variant_priority >= priority_threshold:
yield variant
continue
# Pruning: проверяем consumed_types
if len(variant.consumed_from_types) < min_consumed_types:
continue
# Pruning: проверяем приоритет
variant_priority = variant.injector.priority if isinstance(variant.injector.priority, (int, float)) else 0.0
if variant_priority < priority_threshold:
continue
# Собираем ленивые итераторы для подграфов
subg_iterators = []
for subg in variant.subgraphs:
combinations = list(cls._explode_callgraph_branches_lazy(subg, from_types))
combinations = list(cls._explode_callgraph_branches_lazy(
subg, from_types,
priority_threshold=priority_threshold,
min_consumed_types=min_consumed_types
))
if len(combinations) == 0:
subg_iterators.append([None])
else: