Chronaxis用户手册English
本页目录

chronaxis.planning.backend_selection

源码基线:8904c2f744951857659abd40aaa3535d57faf53c

1"""依据整个计划的静态类别选择数值后端,不读取输入或试跑计算。23auto 只覆盖已测量的简单积分类别。其他组合沿用 NumPy;显式选择始终优先。4选择结果供校验、说明和运行共用,不保存逐条执行记录,也不在失败后重试。5"""67from __future__ import annotations89from dataclasses import dataclass, replace10from typing import TYPE_CHECKING1112if TYPE_CHECKING:13    from ..core.expression import StaticExpression14    from .plan import AnalysisPlan151617BACKENDS = ('reference', 'numpy', 'auto')18_SIMPLE = frozenset(('name', 'const', 'add', 'sub', 'mul', 'div', 'neg', 'abs',19                     'unit_convert', 'to_float'))20_RAW = frozenset(('can_blf', 'can_asc', 'asc_or_blf', 'raw_can_csv'))212223@dataclass(frozen=True)24class BackendSelection:25    """保存一次静态选择:请求值、实际后端及可读原因,不代表已运行。"""2627    requested: str  # 原配置或调用覆盖。28    selected: str  # reference/numpy;非法 typed 声明为 unavailable。29    reason: str  # 解释选择依据,不承诺具体提速比例。303132def simple_numeric_expression(expression: StaticExpression | None) -> bool:33    """检查首批实测的简单数值表达式。参数: 静态表达式。返回: bool。异常: 非法 typed 结构。3435    仅遍历配置树;短路、查表、宿主函数和时序运算留在通用类别。36    """37    if expression is None or not expression.dependencies:38        return False39    from ..core.types import SignalDType40    if expression.root.dtype not in (SignalDType.INT64, SignalDType.UINT64, SignalDType.FLOAT64):41        return False42    pending = [expression.root]43    while pending:44        node = pending.pop()45        if node.operator not in _SIMPLE:46            return False47        pending.extend(node.args)48    return True495051def select_backend(plan: AnalysisPlan) -> BackendSelection:52    """为整个计划选择一次后端。参数: AnalysisPlan。返回: BackendSelection。5354    异常: 非法 typed 结构的属性错误;未知后端作为 unavailable 交给静态诊断。55    不读取 DBC、日志或路径元数据,不修改原计划、身份或用户配置。56    """57    requested = plan.execution.backend58    if requested in ('reference', 'numpy'):59        return BackendSelection(requested, requested, '使用显式指定的数值后端')60    if requested != 'auto':61        return BackendSelection(requested, 'unavailable', '不支持的数值后端')62    conservative = BackendSelection('auto', 'numpy', '该计划不属于已测量的简单积分类别,沿用 NumPy')63    if (plan.extensions is not None or plan.transforms or plan.aggregations or plan.sequences64            or plan.rules or plan.windows or plan.message_calculations or not plan.calculations):65        return conservative66    choices = dict(plan.intervals.resolved)67    used = set()68    for calculation in plan.calculations:69        if (calculation.operation != 'integral' or calculation.scope != 'session'70                or calculation.method != 'zoh' or calculation.condition is not None71                or not simple_numeric_expression(calculation.signal)72                or calculation.calculation_id not in choices73                or choices[calculation.calculation_id].mode != 'actual'):74            return conservative75        used.update(calculation.signal.dependencies)76    definitions = tuple(item.definition for item in plan.signals if item.definition.name in used)77    if {item.name for item in definitions} != used:78        return conservative79    sources = {item.source for item in definitions}80    if len(sources) != 1:81        return conservative82    source = next((item for item in plan.sources if item.name in sources), None)83    if source is None:84        return conservative85    if source.source_type in _RAW and len(definitions) <= 2:86        from ..sources.can_spec import can_field_from_key87        fields = tuple(can_field_from_key(item.field) for item in definitions)88        if len({(f.channel, f.frame_id, f.is_extended, f.is_fd) for f in fields}) == 1:89            return BackendSelection('auto', 'reference', '同一报文定位的简单实际时间积分采用 reference')90    if source.source_type == 'signal_csv' and len(definitions) == 1:91        return BackendSelection('auto', 'reference', '单信号 CSV 实际时间积分采用 reference')92    return conservative939495def execution_plan(plan: AnalysisPlan) -> AnalysisPlan:96    """取得实际执行视图。参数: 原计划。返回: 原计划或仅后端变化的视图。9798    异常: 未支持后端为 ValueError;不修改 raw_config/identity,不重载来源。99    """100    selected = select_backend(plan)101    if selected.selected == 'unavailable':102        raise ValueError('未支持的执行backend:' + str(selected.requested))103    return plan if selected.selected == plan.execution.backend else replace(104        plan, execution=replace(plan.execution, backend=selected.selected))105
Chronaxis 用户手册 · 离线阅读