Chronaxis用户手册English
本页目录

chronaxis.execution.record_delta_condition

源码基线:8904c2f744951857659abd40aaa3535d57faf53c

1"""在当前窗口内保留必要数值片段,输出窗口变化量的三值条件。23实际模式在旧边界移出窗口时继续求值;固定/DBC只在选定驱动到达时移动窗口,4其他更新只处理失效。原实际坐标和TTL不改变,变化量仍交原独立两后端核计算。5"""6from collections import deque7from dataclasses import replace8from fractions import Fraction9from ..core.numeric import ScalarValue10from ..core.types import SignalDType as D,QualityFlag as Q,Truth as T11from ..core.window_delta import DeltaSpan12from ..core.window_delta_reference import window_delta_reference13from ..core.window_delta_numpy import window_delta_numpy14from ..results.errors import ResultClosedError15from ..results.spool import _reserve_owned_ram,_release_owned_ram,_cleanup_owner161718class RecordDeltaCondition:19    """拥有当前窗口片段和有限驱动时刻;不创建整段历史或对照时间轴。"""2021    def __init__(self,budget,spec,dtype,backend,step_ns):22        """预付有限状态,动态窗口按实际容量收费。参数: 预算/配置/数值类型/后端/周期。返回: owner。异常: 原构造错。"""23        self._budget,self._spec,self._dtype,self._step=budget,spec,dtype,step_ns24        self._held_cost=self._fixed_cost=self._span_cost=self._clock_cost=self._work_cost=025        self._spans,self._clocks=deque(),deque()26        self._held_number=self._held_right=None27        self._held_deadline=None28        self._point=self._right=ScalarValue(None,D.BOOL,False,Q.MISSING)29        self._last_time=None30        self.next_deadline=None31        self._closed=self._failed=False32        try:33            _reserve_owned_ram(self,65536,'_fixed_cost')34            self._kernel=window_delta_reference if backend=='reference' else window_delta_numpy35        except BaseException as error:36            _cleanup_owner(self,error,'record_delta_cleanup_owner','窗口变化条件构造')37            raise3839    @staticmethod40    def _condition(result):41        """转换既有数值核的三值结果,不把未知变False。参数: 结果。返回: ScalarValue。异常: 原类型错。"""42        valid=result.condition is not T.UNKNOWN43        return ScalarValue(result.condition is T.TRUE if valid else None,D.BOOL,valid,result.quality)4445    def _append(self,time_ns,point,right):46        """只保存值或质量真正变化的边界,查询末点临时构造。4748        参数: 实际时刻、点值/右侧值。返回: None。异常: 预算/时间回退。49        """50        value=point.value if point.valid else None51        pq=Q.NONE if point.valid else point.quality52        cq=Q.NONE if right.valid else right.quality53        if self._spans:54            last=self._spans[-1]55            if last.start_ns==time_ns:56                self._spans[-1]=DeltaSpan(time_ns,time_ns,value,cq,pq,right.partial,point.partial)57                return58            self._spans[-1]=replace(last,end_ns=time_ns)59            if last.value==value and last.quality==cq==pq and last.partial==right.partial==point.partial:60                return61        _reserve_owned_ram(self,2048,'_span_cost')62        self._spans.append(DeltaSpan(time_ns,time_ns,value,cq,pq,right.partial,point.partial))6364    def _left(self,time_ns):65        """只根据当前窗口需要的驱动记录确定左端。参数: 实际时刻。返回: 左端或不足时None。异常: 无。"""66        if self._step is None:67            return time_ns-self._spec.window_ns68        count=len(self._clocks)69        offset=Fraction(self._spec.window_ns,self._step)70        target=Fraction(count-1)-offset71        if target<0:72            return None73        index=target.numerator//target.denominator74        if target==index:75            return self._clocks[index]76        return round(Fraction(self._clocks[index])+(target-index)*(self._clocks[index+1]-self._clocks[index]))7778    def update(self,time_ns,point,right,expires_at_ns,*,driver=False):79        """推进真实值和当前窗口,返回点/右侧条件;不输出变化值副本。8081        参数: 实际时刻、求值点/右侧值、实际TTL截止及是否选定驱动。82        返回: 两个BOOL ScalarValue。异常: 倒序、预算或原数值错误;失败只能清理。83        """84        if self._closed or self._failed:85            raise ResultClosedError('窗口变化条件已关闭或失败')86        spans=point_result=right_result=None87        try:88            if self._last_time is not None and time_ns<self._last_time:89                raise ValueError('窗口变化时间回退')90            self._last_time=time_ns91            if self._step is not None:92                if driver:93                    if not self._clocks or self._clocks[-1]!=time_ns:94                        _reserve_owned_ram(self,128,'_clock_cost')95                        self._clocks.append(time_ns)96                    limit=(self._spec.window_ns+self._step-1)//self._step+197                    while len(self._clocks)>limit:98                        self._clocks.popleft()99                        _release_owned_ram(self,128,'_clock_cost')100                    self._held_number,self._held_right,self._held_deadline=point,right,expires_at_ns101                else:102                    unknown=ScalarValue(None,self._dtype,False,Q.MISSING)103                    if self._held_number is None:104                        point=right=unknown105                    else:106                        expired=self._held_deadline is not None and time_ns>=self._held_deadline107                        if expired:108                            point=right=ScalarValue(None,self._dtype,False,Q.STALE)109                        else:110                            point=self._held_number if point.valid else point111                            right=self._held_right if right.valid else right112                        if not point.valid or not right.valid:113                            self._held_number,self._held_right=point,right114                self.next_deadline=(self._held_deadline if self._held_deadline is not None and self._held_deadline>time_ns else None)115            self._append(time_ns,point,right)116            if self._step is not None and not driver:117                if not point.valid:118                    self._point=ScalarValue(None,D.BOOL,False,point.quality)119                if not right.valid:120                    self._right=ScalarValue(None,D.BOOL,False,right.quality)121                return self._point,self._right122            left=self._left(time_ns)123            if left is None or left>=time_ns:124                self._point=self._right=ScalarValue(None,D.BOOL,False,Q.MISSING)125                return self._point,self._right126            while len(self._spans)>1 and self._spans[0].end_ns<=left and self._spans[0].start_ns<left:127                self._spans.popleft()128                _release_owned_ram(self,2048,'_span_cost')129            _reserve_owned_ram(self,65536+4096*(len(self._spans)+1),'_work_cost')130            tail=DeltaSpan(time_ns,time_ns,point.value if point.valid else None,131                Q.NONE if right.valid else right.quality,Q.NONE if point.valid else point.quality,right.partial,point.partial)132            spans=tuple(self._spans)133            spans=spans if spans[-1].start_ns==time_ns else spans+(tail,)134            spec=self._spec if self._step is None else replace(self._spec,window_ns=time_ns-left)135            point_result=self._kernel(spec,spans,time_ns,self._dtype)136            right_result=point_result137            if tail.point_quality!=tail.quality:138                right_result=self._kernel(spec,spans[:-1]+(replace(tail,point_quality=tail.quality),),time_ns,self._dtype)139            self._point,self._right=self._condition(point_result),self._condition(right_result)140            # 净变化只依赖端点数值,要求单调时中间实际观测值也参与判断。141            history_partial=any((s.point_partial if s.start_ns==left else s.partial)142                                for s in spans if s.start_ns<=left<s.end_ns)143            if spec.monotonic:144                history_partial|=any(s.point_partial for s in spans if left<s.start_ns<time_ns)145            if self._point.valid and (history_partial or point.partial):146                self._point=replace(self._point,partial=True)147            if self._right.valid and (history_partial or right.partial):148                self._right=replace(self._right,partial=True)149            if self._step is None:150                candidates=[span.start_ns+self._spec.window_ns for span in self._spans151                            if time_ns<span.start_ns+self._spec.window_ns<(1<<63)]152                if expires_at_ns is not None and expires_at_ns>time_ns:153                    candidates.append(expires_at_ns)154                self.next_deadline=min(candidates) if candidates else None155            return self._point,self._right156        except BaseException:157            self._failed=True158            raise159        finally:160            spans=point_result=right_result=None161            _release_owned_ram(self,self._work_cost,'_work_cost')162163    @property164    def closed(self):165        """返回资源关闭状态。参数: 无。返回: bool。异常: 无。"""166        return self._closed167168    def close(self):169        """释放有界片段与驱动记录,不写文件。参数: 无。返回: None。异常: 原预算关闭错,可重试。"""170        if self._closed:171            return172        self._spans.clear();self._clocks.clear()173        self._held_number=self._held_right=None174        for slot in ('_span_cost','_clock_cost','_work_cost','_fixed_cost'):175            _release_owned_ram(self,getattr(self,slot),slot)176        self._closed=True177
Chronaxis 用户手册 · 离线阅读