Chronaxis用户手册English
本页目录

chronaxis.core.sample_reduction

源码基线:8904c2f744951857659abd40aaa3535d57faf53c

1"""声明有限样本统计事实、数值快照与结构门槛,不执行样本归约。23支持样本极值、均值、计数、方差、标准差、RMS及精确分位数。BOOL条件可省略为全TRUE。值有效与条件4已知分别完整划分实际窗口;FALSE不选择,UNKNOWN不当FALSE。真实样本仅计半开5窗口内原值实际更新且有效/TRUE,TTL、条件更新和裁剪保持边界不能成为样本。6mean的值覆盖包含整数转float精度门槛,求和、除法和单位故障单独记数值失败。7纯协议不读来源、不管理预算、不保存全轴;有限元数据及结果由外层owner计费。8"""910# 两数值后端仅共享冻结协议、单位和几何校验,数值与覆盖计算各自独立。11from .moments import SAMPLE_MOMENTS12from .quantiles import SAMPLE_QUANTILES13from dataclasses import dataclass14from math import isfinite15from .integral_sum import require_partial_limit16from .calculations import CalculationSeries, CalculationDefinition, calculation_conversion17from .models import Interval, SourceRef18from .types import QualityFlag as Q, SignalDType as D19from .validation import require_text202122def _unknown_duration(ranges, actual):23    """校验一种未知范围并精确累计纳秒,不用总长度掩盖重复位置。2425    参数: ranges为冻结正Interval tuple;actual为原请求内交集或None。26    返回: 原生int未知总时长。异常: TypeError/ValueError为类型、反序、重叠或越界。27    """28    # 值和条件各自执行本结构检查,不能互相补充另一种覆盖缺口。29    if type(ranges) is not tuple:30        raise TypeError('样本事实未知范围需要tuple')31    cursor, total = (actual.start_ns if actual is not None else 0), 032    for item in ranges:33        if (not isinstance(item, Interval) or actual is None or item.start_ns < cursor34                or item.start_ns >= item.end_ns or item.end_ns > actual.end_ns):35            raise ValueError('样本未知范围必须有序、不重叠且在实际窗口内')36        cursor, total = item.end_ns, total + item.end_ns - item.start_ns37    return total383940@dataclass(frozen=True)41class SampleCalculationFacts:42    """保存有限块双覆盖与真实选中样本,样本数不代替区间数或时长。4344    selected只计条件TRUE且数值可用的正时长,selected_value_unknown只计TRUE值未知。45    无条件known等于实际跨度、false为0;mean精度失败属于值未知,数值累计失败不改事实。46    """4748    spec: CalculationDefinition  # 原samples请求、scope与覆盖政策。49    actual_window: Interval | None  # 当前块真实交集,不外推EOF。50    value_valid_duration_ns: int  # 通过本算子值门槛的有效纳秒。51    condition_known_duration_ns: int  # 条件可判断TRUE/FALSE的纳秒。52    selected_duration_ns: int  # 条件TRUE且值有效的保持纳秒,不是样本分母。53    selected_value_unknown_duration_ns: int  # TRUE但值未知的纳秒。54    false_duration_ns: int  # 明确FALSE纳秒,不包含条件UNKNOWN。55    valid_sample_count: int  # 半开窗口中有效/TRUE的原值真实更新。56    value_unknown_ranges: tuple[Interval, ...]  # 原值和mean精度未知位置。57    condition_unknown_ranges: tuple[Interval, ...]  # 独立BOOL UNKNOWN位置。58    quality: Q  # 输入、精度与依赖原因,不含归约数值故障。59    input_unit: str  # 原分析工程单位,未最终转换。60    dtype: D  # 原数值声明,极值保持int64/uint64精确整数。61    binding_identity: str  # 原值联合输入实际身份。62    source_refs: tuple[SourceRef, ...]  # 完整来源定位,保留真实子类。6364    def __post_init__(self):65        """核对完整双分区、选择交集及typed字段,不修补事实。6667        参数: 无。返回: None。异常: TypeError/ValueError为配置、覆盖、类型或几何矛盾。68        """69        # 结构配置不执行数值转换,只检查样本统计能力与单位。70        require_sample_config(self.spec, self.input_unit, self.dtype, 4096)71        if self.actual_window is not None and not isinstance(self.actual_window, Interval):72            raise TypeError('样本实际范围需要Interval或None')73        actual, request = self.actual_window, self.spec.window74        span = 0 if actual is None else actual.end_ns - actual.start_ns75        if actual is not None and not request.start_ns <= actual.start_ns <= actual.end_ns <= request.end_ns:76            raise ValueError('样本事实实际范围超出原请求')77        durations = (self.value_valid_duration_ns, self.condition_known_duration_ns, self.selected_duration_ns,78                     self.selected_value_unknown_duration_ns, self.false_duration_ns)79        # 原生整数纳秒与计数不能接受bool/浮点;TRUE值未知不能超过全部值未知。80        if (any(type(value) is not int or not 0 <= value <= span for value in durations)81                or type(self.valid_sample_count) is not int or not 0 <= self.valid_sample_count <= self.selected_duration_ns82                or self.selected_duration_ns > self.value_valid_duration_ns83                or self.selected_value_unknown_duration_ns > span - self.value_valid_duration_ns84                or self.false_duration_ns > self.condition_known_duration_ns85                or self.selected_duration_ns + self.selected_value_unknown_duration_ns86                   != self.condition_known_duration_ns - self.false_duration_ns):87            raise ValueError('样本事实计数、选择与双覆盖交集矛盾')88        if _unknown_duration(self.value_unknown_ranges, actual) + self.value_valid_duration_ns != span:89            raise ValueError('样本值有效与未知未完整划分实际窗口')90        if _unknown_duration(self.condition_unknown_ranges, actual) + self.condition_known_duration_ns != span:91            raise ValueError('样本条件已知与未知未完整划分实际窗口')92        # 完整来源和质量保持真实类型,不将文件名或自由文字当作来源证据。93        if not isinstance(self.quality, Q) or type(self.source_refs) is not tuple or any(not isinstance(ref, SourceRef) for ref in self.source_refs):94            raise TypeError('样本事实需要typed质量和完整来源tuple')95        require_text(self.binding_identity, 'sample.binding_identity')969798@dataclass(frozen=True)99class SampleReductionResult:100    """保存最终单位数值与真实样本数,不复用时间统计的区间项数语义。101102    极值可保留精确int,均值为float;有效零、无样本None和数值失败分别表示。103    输入覆盖与最终report/strict/空选择分类由外层负责,数值快照不补正常零。104    """105106    value: int | float | None  # 最终单位有限候选,无法核实为None。107    unit: str  # 最终输出标签,已换单位一次。108    calculation_failed: bool  # 原序和、除法或最终转换失败。109    quality: Q  # 仅数值故障,输入原因另存facts。110    valid_sample_count: int  # 实际参与候选的有效真实样本数。111    insufficient_samples: bool = False  # 单个样本无法定义ddof=1的离散度。112113    def __post_init__(self):114        """拒绝样本数、正常数值和失败状态之间的矛盾。115116        参数: 无。返回: None。异常: TypeError/ValueError为字段类型或不可能数值状态。117        """118        # 非有限/bool不能成为正常候选,原整数不被float检查造成舍入。119        require_text(self.unit, 'sample.output_unit')120        if self.value is not None and (type(self.value) not in (int, float)121                or type(self.value) is float and not isfinite(self.value)):122            raise ValueError('样本结果需要有限int/float或None')123        if (type(self.calculation_failed) is not bool or not isinstance(self.quality, Q)124                or type(self.valid_sample_count) is not int or self.valid_sample_count < 0):125            raise TypeError('样本结果需要真实失败状态、质量和非负原生int计数')126        # 空样本只能无值;有效失败须有样本及原因,成功不带数值故障位。127        if type(self.insufficient_samples) is not bool:128            raise TypeError('不足样本标志需要bool')129        if self.insufficient_samples:130            if self.valid_sample_count != 1 or self.value is not None or self.calculation_failed or self.quality != Q.NONE:131                raise ValueError('自由度不足必须保留一个有效样本及无数值状态')132        elif self.calculation_failed:133            if self.value is not None or self.quality == Q.NONE or self.valid_sample_count == 0:134                raise ValueError('样本数值失败需要有效样本、None与明确原因')135        elif self.quality != Q.NONE or (self.valid_sample_count == 0) != (self.value is None):136            raise ValueError('样本成功结果数值、计数或质量矛盾')137138139def require_sample_config(spec, input_unit, dtype, partial_limit):140    """校验三samples能力、数值dtype与明确单位,不计算样本。141142    参数: 原spec/input_unit/dtype及正原生int误差容量partial_limit。143    返回: CalculationConversion。异常: TypeError/ValueError为类型、能力、单位或容量。144    """145    # BOOL/ENUM与时间算子各有独立口径,不在本核中暗自提升或扩展。146    if not isinstance(spec, CalculationDefinition) or spec.operation not in ('sample_count', 'sample_minimum', 'sample_maximum', 'sample_mean', *SAMPLE_MOMENTS, *SAMPLE_QUANTILES):147        raise TypeError('样本归约需要已支持的样本统计操作')148    if not isinstance(dtype, D) or dtype not in (D.INT64, D.UINT64, D.FLOAT64):149        raise ValueError('样本统计只接受数值dtype')150    require_text(input_unit, 'sample.input_unit')151    require_partial_limit(partial_limit)152    return calculation_conversion(spec, input_unit)153154155def require_sample_series(series, spec, input_unit, dtype):156    """核对有限输入unit/dtype及精确交集,保留可选BOOL条件。157158    参数: series为有限CalculationSeries,其余为归约原配置。159    返回: 实际交集Interval或None。异常: TypeError/ValueError/OverflowError。160    """161    # CalculationSeries已校验可选条件列为BOOL;不自动换单位、转dtype或补原值更新。162    if not isinstance(series, CalculationSeries):163        raise TypeError('样本归约需要CalculationSeries')164    if series.unit != input_unit or series.values[0].dtype is not dtype:165        raise ValueError('样本归约只接受同unit及同dtype输入')166    left, right = max(spec.window.start_ns, series.observation.start_ns), min(spec.window.end_ns, series.observation.end_ns)167    if right-left > 2**63-1:168        raise OverflowError('样本正交集跨度超过int64')169    return Interval(left, right) if left <= right else None170
Chronaxis 用户手册 · 离线阅读