整合求解器活动监控与步长回归证据

同步远端 PNL0003 诊断和大采样网格能力,语义合并活动感知的 60 秒真停滞判定与旧后端 15 分钟兼容兜底。

纳管热路径优化、15 单元运行证据、浏览器与 API 报告,并补充北京时间更新日志和遗留问题。
This commit is contained in:
lujingze committed 2026-08-19 16:24:31 +00:00
1 parent c19cf77aee
commit e18399c022
46 files changed
+181589 -170

No files matched your search

+75 -7
View File
@@ -399,6 +399,19 @@ def _case_observation(
checkpoint_details.append(detail)
if not detail["available"]:
issues.append("checkpointUnavailable")
requested_time = checkpoint.get("requestedTime")
actual_time = checkpoint.get("actualTime")
if (
not isinstance(requested_time, (int, float))
or not isinstance(actual_time, (int, float))
or not math.isclose(
float(requested_time),
float(actual_time),
rel_tol=0.0,
abs_tol=tolerance.checkpoint_time_absolute_seconds,
)
):
issues.append("checkpointTimeMismatch")
if expected_projection_count is not None and len(state_values) != int(
expected_projection_count
):
@@ -455,6 +468,7 @@ def _pair_checkpoints(
right: Mapping[str, object],
*,
tolerance: MatrixTolerance,
strict_prefix_stop: float | None = None,
) -> dict[str, object]:
left_checkpoints = _checkpoints(_summary(left))
right_checkpoints = _checkpoints(_summary(right))
@@ -463,6 +477,11 @@ def _pair_checkpoints(
left_time = left_checkpoint.get("requestedTime")
if not isinstance(left_time, (int, float)):
continue
if strict_prefix_stop is not None and not (
float(left_time)
< strict_prefix_stop - tolerance.checkpoint_time_absolute_seconds
):
continue
match = next(
(
right_checkpoint
@@ -554,6 +573,7 @@ def _pair_checkpoints(
"commonCheckpointTimes": [
pair[0].get("requestedTime") for pair in paired
],
"strictPrefixStopTime": strict_prefix_stop,
"valueMismatchCount": mismatch_count,
"keySetMismatchCount": key_set_mismatch_count,
"nonnumericValueCount": nonnumeric_count,
@@ -569,6 +589,7 @@ def _compare_time_sequences(
*,
prefix_stop: float,
absolute_tolerance: float,
strict_prefix: bool,
) -> dict[str, object]:
left_times = _finite_event_times(left)
right_times = _finite_event_times(right)
@@ -579,12 +600,12 @@ def _compare_time_sequences(
"left": left,
"right": right,
}
left_prefix = [
value for value in left_times if value <= prefix_stop + absolute_tolerance
]
right_prefix = [
value for value in right_times if value <= prefix_stop + absolute_tolerance
]
if strict_prefix:
include = lambda value: value < prefix_stop - absolute_tolerance
else:
include = lambda value: value <= prefix_stop + absolute_tolerance
left_prefix = [value for value in left_times if include(value)]
right_prefix = [value for value in right_times if include(value)]
passed = len(left_prefix) == len(right_prefix) and all(
math.isclose(
left_value,
@@ -607,6 +628,7 @@ def _pair_events(
right: Mapping[str, object],
*,
prefix_stop: float,
strict_prefix: bool,
tolerance: MatrixTolerance,
) -> dict[str, object]:
left_trace = _event_trace(_summary(left))
@@ -616,12 +638,14 @@ def _pair_events(
right_trace.get("signalEventTimes"),
prefix_stop=prefix_stop,
absolute_tolerance=tolerance.signal_event_time_absolute_seconds,
strict_prefix=strict_prefix,
)
mechanical = _compare_time_sequences(
left_trace.get("mechanicalTransitionTimes"),
right_trace.get("mechanicalTransitionTimes"),
prefix_stop=prefix_stop,
absolute_tolerance=tolerance.event_time_absolute_seconds,
strict_prefix=strict_prefix,
)
availability = (
left_trace.get("mechanicalTransitionTimesAvailable") is not False
@@ -631,6 +655,7 @@ def _pair_events(
"evaluated": bool(left_trace) and bool(right_trace),
"passed": bool(signal["passed"] and mechanical["passed"] and availability),
"prefixStopTime": prefix_stop,
"strictPrefix": strict_prefix,
"signalEventTimes": signal,
"mechanicalTransitionTimes": mechanical,
"mechanicalTransitionTimesAvailable": availability,
@@ -701,17 +726,29 @@ def compare_matrix_cases(
left_stop = float(left["stopTime"])
right_stop = float(right["stopTime"])
prefix_stop = min(left_stop, right_stop)
strict_prefix = not math.isclose(
left_stop,
right_stop,
rel_tol=0.0,
abs_tol=tolerance.checkpoint_time_absolute_seconds,
)
if not _completed(left, left_stop) or not _completed(right, right_stop):
return {
"evaluated": False,
"passed": False,
"reason": "oneOrBothCasesDidNotComplete",
}
state = _pair_checkpoints(left, right, tolerance=tolerance)
state = _pair_checkpoints(
left,
right,
tolerance=tolerance,
strict_prefix_stop=prefix_stop if strict_prefix else None,
)
events = _pair_events(
left,
right,
prefix_stop=prefix_stop,
strict_prefix=strict_prefix,
tolerance=tolerance,
)
diagnostics = _pair_diagnostics(
@@ -728,6 +765,7 @@ def compare_matrix_cases(
"evaluated": True,
"passed": passed,
"commonPrefixStopTime": prefix_stop,
"strictPrefix": strict_prefix,
"stateProjection": state,
"events": events,
"diagnostics": diagnostics,
@@ -874,6 +912,36 @@ def run_max_step_matrix(
if sampling_mode == "source"
else _finite_positive(lane_config.get("sampleStep"), field="lane.sampleStep")
)
source_start = float(source_config["tStart"])
checkpoint_grid_tolerance = max(
1.0e-12,
8.0 * math.ulp(max(1.0, abs(source_start))),
8.0 * math.ulp(max(1.0, abs(sample_step))),
)
for horizon in selected_horizons:
for checkpoint_time in horizon.checkpoint_times:
if math.isclose(
checkpoint_time,
horizon.stop_time,
rel_tol=0.0,
abs_tol=checkpoint_grid_tolerance,
):
continue
grid_index = round((checkpoint_time - source_start) / sample_step)
grid_time = source_start + grid_index * sample_step
if not math.isclose(
checkpoint_time,
grid_time,
rel_tol=0.0,
abs_tol=checkpoint_grid_tolerance,
):
raise RegressionManifestError(
"Matrix checkpoint "
f"{checkpoint_time:.17g} is not represented by the "
f"{sample_step:.17g} s output grid for "
f"{horizon.case_id!r}; use the event trace for off-grid "
"transition times."
)
instrumentation_mode = str(
lane_config.get("instrumentationMode", "standard")
)