"""Frozen real-data runner for the label-blind geometry certificate audit.""" from __future__ import annotations import argparse import hashlib import json import math import os from collections.abc import Sequence from dataclasses import asdict, dataclass, replace from datetime import datetime from pathlib import Path from typing import Any import numpy as np import torch import torch.nn.functional as functional import yaml from PIL import Image from torch import Tensor from mcss.data.manifest import SceneManifest, load_manifest from mcss.geometry import transform_cameras from mcss.geometry_certificates import ( CertificateBuildResult, CertificateConfig, GeometryCertificate, RawObservation, build_certificates, triangulate_dlt, ) from mcss.types import Cameras @dataclass(frozen=True) class AuditDecisionThresholds: minimum_windows: int = 32 minimum_certified_coverage: float = 0.15 minimum_nonzero_window_fraction: float = 0.80 maximum_median_error_m: float = 0.25 maximum_p90_error_m: float = 0.50 maximum_permutation_delta_m: float = 1e-4 minimum_shuffled_error_ratio: float = 1.5 minimum_shuffled_error_margin_m: float = 0.05 minimum_risk_error_spearman: float = 0.0 def __post_init__(self) -> None: if self.minimum_windows < 1: raise ValueError("minimum_windows must be positive") if not 0.0 <= self.minimum_certified_coverage <= 1.0: raise ValueError("minimum_certified_coverage must be in [0, 1]") if not 0.0 <= self.minimum_nonzero_window_fraction <= 1.0: raise ValueError("minimum_nonzero_window_fraction must be in [0, 1]") if min( self.maximum_median_error_m, self.maximum_p90_error_m, self.maximum_permutation_delta_m, self.minimum_shuffled_error_ratio, self.minimum_shuffled_error_margin_m, ) < 0: raise ValueError("decision thresholds must be nonnegative") if not -1.0 <= self.minimum_risk_error_spearman <= 1.0: raise ValueError("minimum_risk_error_spearman must be in [-1, 1]") @dataclass(frozen=True) class GeometryAuditConfig: seed: int dataset_root: str output_dir: str context_views: int image_size: tuple[int, int] window_count: int window_stride: int permutation_windows: int local_bounds_m: tuple[tuple[float, float, float], tuple[float, float, float]] voxel_resolution: tuple[int, int, int] certificate: CertificateConfig decision: AuditDecisionThresholds def __post_init__(self) -> None: if self.context_views < 3: raise ValueError("context_views must be at least three") if min(*self.image_size, self.window_count, self.window_stride) < 1: raise ValueError("image/window values must be positive") if not 0 <= self.permutation_windows <= self.window_count: raise ValueError("permutation_windows must be in [0, window_count]") if min(self.voxel_resolution) < 1: raise ValueError("voxel_resolution values must be positive") lower, upper = self.local_bounds_m if any(low >= high for low, high in zip(lower, upper, strict=True)): raise ValueError("local_bounds_m must have increasing bounds") def select_frozen_windows( entries: Sequence[tuple[str, int]], *, count: int, seed: int ) -> list[tuple[str, int]]: """Select scene-balanced windows by stable hashes, independent of input ordering.""" if count < 1: raise ValueError("count must be positive") unique = set(entries) if len(unique) < count: raise ValueError(f"requested {count} windows but only {len(unique)} are available") by_scene: dict[str, list[int]] = {} for scene_id, start in unique: if not scene_id or start < 0: raise ValueError("window entries require non-empty scene IDs and nonnegative starts") by_scene.setdefault(scene_id, []).append(start) scene_order = sorted(by_scene, key=lambda scene: _stable_hash_int(seed, scene)) starts = { scene: sorted(values, key=lambda start: _stable_hash_int(seed, scene, str(start))) for scene, values in by_scene.items() } selected: list[tuple[str, int]] = [] round_index = 0 while len(selected) < count: added = False for scene in scene_order: if round_index < len(starts[scene]): selected.append((scene, starts[scene][round_index])) added = True if len(selected) == count: break if not added: raise RuntimeError("window selection exhausted entries unexpectedly") round_index += 1 return selected def decide_audit( metrics: dict[str, Any], thresholds: AuditDecisionThresholds ) -> dict[str, Any]: """Apply the pre-registered all-gates decision without threshold tuning.""" required = { "window_count", "certified_coverage_macro", "nonzero_window_fraction", "geometry_error_median_m", "geometry_error_p90_m", "matched_confidence_median_error_m", "permutation_max_point_delta_m", "shuffled_median_error_m", "risk_error_spearman", } missing = sorted(key for key in required if metrics.get(key) is None) if missing or int(metrics.get("window_count", 0)) < thresholds.minimum_windows: return { "status": "INCONCLUSIVE", "gates": {}, "missing": missing, "reason": "required metrics or frozen window count are incomplete", } certified_error = float(metrics["geometry_error_median_m"]) shuffled_error = float(metrics["shuffled_median_error_m"]) gates = { "certified_coverage": float(metrics["certified_coverage_macro"]) >= thresholds.minimum_certified_coverage, "nonzero_windows": float(metrics["nonzero_window_fraction"]) >= thresholds.minimum_nonzero_window_fraction, "median_geometry_error": certified_error <= thresholds.maximum_median_error_m, "p90_geometry_error": float(metrics["geometry_error_p90_m"]) <= thresholds.maximum_p90_error_m, "beats_confidence_at_matched_coverage": certified_error < float(metrics["matched_confidence_median_error_m"]), "view_permutation_invariance": float(metrics["permutation_max_point_delta_m"]) <= thresholds.maximum_permutation_delta_m, "shuffled_correspondence_degrades": ( shuffled_error >= certified_error * thresholds.minimum_shuffled_error_ratio and shuffled_error >= certified_error + thresholds.minimum_shuffled_error_margin_m ), "risk_predicts_geometry_error": float(metrics["risk_error_spearman"]) > thresholds.minimum_risk_error_spearman, } return { "status": ( "GO_TO_STATE_INTEGRATION" if all(gates.values()) else "STOP_CERTIFICATE_FRONTEND" ), "gates": gates, "missing": [], "reason": "all frozen gates passed" if all(gates.values()) else "one or more gates failed", } def render_markdown_report( decision: dict[str, Any], metrics: dict[str, Any], *, config_path: Path, artifact_paths: Sequence[Path], started_at: str, finished_at: str, ) -> str: """Render the Chinese-first terminal audit report, including absent formal roles.""" status = decision.get("status", "INCONCLUSIVE") gates = decision.get("gates", {}) artifact_lines = "\n".join(f"- `{path}`" for path in artifact_paths) or "- none recorded" gate_lines = ( "\n".join( f"- `{name}`: {'PASS' if passed else 'FAIL'}" for name, passed in gates.items() ) or "- none recorded" ) institute_roles = "\n".join( f"- {role}: not invoked" for role in ( "research director", "framing architect", "domain scientist", "evidence curator", "model scientist", "experiment statistician", "software executor", "independent validator", "venue editor", ) ) return f"""# 几何认证写保护场景状态:零训练审计报告 ## 1. Identity - 项目:Measurement-Complete Scene State - 阶段:geometry-certificate label-blind audit - 状态:`{status}` - 开始:`{started_at}` - 结束:`{finished_at}` - 配置:`{config_path}` - 路由说明:本阶段承接中档超级科研准备,但不是正式 Research Institute 运行。 ## 2. Objective And Scope 这次只回答一个问题:不读取 target RGB/depth/normal,也不训练网络时,context RGB 与 标定相机能否产生覆盖足够、几何正确、可追溯的三维证书。V5、V6a、V6a.1、固定 renderer 和主干均未修改。训练及 typed-state 接入由本报告的冻结门槛控制。 ## 3. Materials And Provenance {artifact_lines} 证书构造仅接收 context RGB 和 context cameras。每个窗口的 certificate JSON 写盘之后, runner 才打开对应 context depth 做事后评分。运行根目录强制为 development `train`; diagnostic-test 和 final-holdout 未授权、未读取。 ## 4. Research Route V6a.1 已封存,因为局部 RGB 竞争并不定位真实表面。本阶段换成“LoFTR 只提候选,固定 几何决定能否写入”的审计路径。认证顺序为 raw -> reciprocal -> cycle -> epipolar / cheirality / triangulation -> third-view reprojection。任何一步失败都保留为拒绝计数, 不会交给 completion 掩盖。 ## 5. Decision Audit 最终判定:`{status}`。理由:{decision.get('reason', 'not recorded')}。 {gate_lines} 关键汇总: - 冻结窗口数:`{_format_metric(metrics.get('window_count'))}` - 认证 source-grid coverage:`{_format_metric(metrics.get('certified_coverage_macro'))}` - 非零窗口比例:`{_format_metric(metrics.get('nonzero_window_fraction'))}` - 几何误差 median / p90:`{_format_metric(metrics.get('geometry_error_median_m'))}` m / `{_format_metric(metrics.get('geometry_error_p90_m'))}` m - 同覆盖 LoFTR confidence median: `{_format_metric(metrics.get('matched_confidence_median_error_m'))}` m - shuffled correspondence median:`{_format_metric(metrics.get('shuffled_median_error_m'))}` m - 视图置换最大点偏差:`{_format_metric(metrics.get('permutation_max_point_delta_m'))}` m - 风险-误差 Spearman:`{_format_metric(metrics.get('risk_error_spearman'))}` ## 6. Research Institute Record 正式 Institute MCP/route 本阶段不可用,因此以下正式角色均未实例化: {institute_roles} 先前参与方向准备的 Curie、Boyle、Parfit 仅是降级独立顾问,不得冒充正式 Institute 记录或 PASS。他们共同建议 A+B 合同,并要求先做本次标签盲审计。 ## 7. Evaluation Council Record Council not convened。没有 frozen dossier、七席有效 ballot、独立 rescore 或 clerk gate, 因此本报告不能声称 Council PASS。 ## 8. Tools And Collaborators - 实现:Python 3.11、PyTorch、Kornia LoFTR、pytest、Ruff。 - proposer:冻结的 ScanNet `indoor_new` LoFTR;它只提候选,不是论文创新。 - geometry:fundamental matrix、互惠、三视图循环、DLT、cheirality、重投影。 - 文献补查:arXiv 接口返回 HTTP 429;NeuralRecon/TransformerFusion/TSDF/scene completion 的正式等价性复核仍未完成。 - Generation 10 completion-report 仍是设计;当前激活生态是 Generation 9。 ## 9. Outputs And Verification 本次新增功能的聚焦测试、静态检查、运行日志及哈希见 artifact 列表。最终人工交付检查 另记录全仓测试与 Ruff 边界。结果状态只代表本阶段的机制审计,不代表训练有效、外部 基线胜出或 CVPR-ready。 ## 10. Risks And Open Issues - LoFTR 先验可能主导候选质量,后续必须做同 proposer 的合同对照。 - context depth 仅用于写盘后的审计;它不能成为模型输入或阈值选择依据。 - 匹配、三角化、free/unknown、TSDF/occupancy 各自均非新意。 - NeuralRecon、TransformerFusion 和 observation-preserving completion 的等价性仍待补查。 - 即使本审计 GO,也只允许实现 write-protected typed state,不允许直接声称 CVPR 水平。 ## 11. Memory Disposition 本次结果未写入项目或全局记忆。项目没有 `.codex-memory`,用户也没有要求更新外部 memory。失败证据和审计产物只保存在本项目 `outputs` 与 `docs` 中。 ## 12. Next Step `GO_TO_STATE_INTEGRATION` 只授权下一阶段设计:将 conditional free prefix、surface interval、behind-surface unknown、conflict 和 provenance 接入独立 typed state,并做 write-protection intervention。`STOP_CERTIFICATE_FRONTEND` 则封存该 frontend,不进入 训练;`INCONCLUSIVE` 只允许补齐缺失运行,不允许调阈值。 """ def load_audit_config(path: str | Path) -> GeometryAuditConfig: config_path = Path(path) raw = yaml.safe_load(config_path.read_text(encoding="utf-8")) if not isinstance(raw, dict): raise ValueError("audit config root must be a mapping") allowed = { "seed", "dataset_root", "output_dir", "context_views", "image_size", "window_count", "window_stride", "permutation_windows", "local_bounds_m", "voxel_resolution", "certificate", "decision", } unknown = set(raw) - allowed if unknown: raise ValueError(f"unknown audit config keys: {sorted(unknown)}") missing = allowed - set(raw) if missing: raise ValueError(f"missing audit config keys: {sorted(missing)}") certificate_raw = dict(raw["certificate"]) decision_raw = dict(raw["decision"]) return GeometryAuditConfig( seed=int(raw["seed"]), dataset_root=str(raw["dataset_root"]), output_dir=str(raw["output_dir"]), context_views=int(raw["context_views"]), image_size=_pair(raw["image_size"], "image_size"), window_count=int(raw["window_count"]), window_stride=int(raw["window_stride"]), permutation_windows=int(raw["permutation_windows"]), local_bounds_m=_bounds(raw["local_bounds_m"]), voxel_resolution=_triple(raw["voxel_resolution"], "voxel_resolution"), certificate=CertificateConfig(**certificate_raw), decision=AuditDecisionThresholds(**decision_raw), ) def run_audit(config_path: str | Path) -> dict[str, Any]: config_file = Path(config_path).resolve() config = load_audit_config(config_file) output_dir = Path(config.output_dir).resolve() if output_dir.exists(): raise FileExistsError(f"refusing to overwrite audit output: {output_dir}") root = Path(config.dataset_root).resolve() if root.name != "train" or any( token in str(root).lower() for token in ("diagnostic_test", "final_holdout") ): raise ValueError("geometry audit is restricted to the prepared development train root") manifests = {path.parent.name: path for path in sorted(root.glob("*/manifest.json"))} if not manifests: raise FileNotFoundError(f"no direct scene manifests found below {root}") entries: list[tuple[str, int]] = [] frame_ids_by_scene: dict[str, list[int]] = {} for scene_id, manifest_path in manifests.items(): manifest = load_manifest(manifest_path) frame_ids_by_scene[scene_id] = [frame.frame_id for frame in manifest.frames] entries.extend( (scene_id, start) for start in range( 0, len(manifest.frames) - config.context_views + 1, config.window_stride, ) ) selected = select_frozen_windows(entries, count=config.window_count, seed=config.seed) started_at = _now() output_dir.mkdir(parents=True) certificate_dir = output_dir / "certificates" certificate_dir.mkdir() frozen_windows = [] for scene_id, start in selected: ids = frame_ids_by_scene[scene_id][start : start + config.context_views] frozen_windows.append( { "scene_id": scene_id, "start": start, "frame_ids": ids, "manifest": str(manifests[scene_id]), } ) _atomic_json( output_dir / "frozen_windows.json", { "seed": config.seed, "selection_rule": "scene-balanced sha256 ordering", "partition": "train", "windows": frozen_windows, }, ) window_metrics: list[dict[str, Any]] = [] accessed_depth_paths: list[str] = [] permutation_deltas: list[float] = [] all_errors: list[float] = [] all_risks: list[float] = [] all_confidence_errors: list[tuple[float, float]] = [] all_shuffled_errors: list[float] = [] all_camera_shuffled_errors: list[float] = [] for window_index, window in enumerate(frozen_windows): manifest = load_manifest(window["manifest"]) frames = manifest.frames[window["start"] : window["start"] + config.context_views] context_rgb, cameras = _load_context_rgb_and_cameras(manifest, frames, config.image_size) build = build_certificates(context_rgb, cameras, config.certificate) certificate_path = certificate_dir / f"window_{window_index:03d}.json" certificate_written_at = _now() _atomic_json( certificate_path, { "schema_version": 1, "scene_id": window["scene_id"], "start": window["start"], "frame_ids": window["frame_ids"], "certificate_config": asdict(config.certificate), "label_inputs_to_builder": [], "written_at": certificate_written_at, "build": build.to_dict(), }, ) depth_loaded_at = _now() depths, depth_paths = _load_context_depth(manifest, frames, config.image_size) accessed_depth_paths.extend(str(path) for path in depth_paths) evaluation = _evaluate_window(build, depths, cameras, config) if depth_loaded_at < certificate_written_at: raise RuntimeError("depth access timestamp preceded certificate serialization") evaluation.update( { "window_index": window_index, "scene_id": window["scene_id"], "start": window["start"], "certificate_path": str(certificate_path), "certificate_sha256": _sha256(certificate_path), "certificate_written_at": certificate_written_at, "depth_loaded_at": depth_loaded_at, "stage_counts": build.stage_counts, "certified_source_coverage": build.certified_source_coverage, } ) window_metrics.append(evaluation) all_errors.extend(evaluation.pop("geometry_errors_m")) all_risks.extend(evaluation.pop("risks")) all_confidence_errors.extend( (float(item[0]), float(item[1])) for item in evaluation.pop("raw_confidence_and_errors_m") ) all_shuffled_errors.extend(evaluation.pop("shuffled_errors_m")) all_camera_shuffled_errors.extend(evaluation.pop("camera_shuffled_errors_m")) if window_index < config.permutation_windows: order = torch.tensor([2, 0, 3, 1], dtype=torch.long)[: config.context_views] permuted = build_certificates( context_rgb[order], cameras.select_views(order), config.certificate ) permutation_deltas.append(_point_set_delta(build, permuted)) _append_jsonl(output_dir / "window_metrics.jsonl", evaluation) confidence_errors = _matched_confidence_errors( all_confidence_errors, target_count=len(all_errors) ) metrics = _aggregate_metrics( window_metrics, geometry_errors=all_errors, risks=all_risks, confidence_errors=confidence_errors, shuffled_errors=all_shuffled_errors, camera_shuffled_errors=all_camera_shuffled_errors, permutation_deltas=permutation_deltas, ) decision = decide_audit(metrics, config.decision) finished_at = _now() result = { "schema_version": 1, "status": decision["status"], "started_at": started_at, "finished_at": finished_at, "config_path": str(config_file), "config_sha256": _sha256(config_file), "dataset_root": str(root), "partition": "train", "final_or_diagnostic_access": False, "certificate_before_depth": True, "metrics": metrics, "decision": decision, "certificate_config": asdict(config.certificate), "decision_thresholds": asdict(config.decision), "weight_artifacts": _weight_artifacts(Path(config.certificate.model_cache_dir)), } _atomic_json(output_dir / "audit_result.json", result) _atomic_json( output_dir / "access_log.json", { "dataset_root": str(root), "partition": "train", "depth_files_opened_after_certificate_write": sorted(set(accessed_depth_paths)), "diagnostic_or_final_access": False, }, ) artifacts = [ output_dir / "audit_result.json", output_dir / "frozen_windows.json", output_dir / "window_metrics.jsonl", output_dir / "access_log.json", certificate_dir, ] report = render_markdown_report( decision, metrics, config_path=config_file, artifact_paths=artifacts, started_at=started_at, finished_at=finished_at, ) (output_dir / "REPORT.md").write_text(report, encoding="utf-8") _atomic_json( output_dir / "artifact_hashes.json", { str(path.relative_to(output_dir)): _sha256(path) for path in output_dir.rglob("*") if path.is_file() and path.name != "artifact_hashes.json" }, ) return result def main(argv: Sequence[str] | None = None) -> int: parser = argparse.ArgumentParser(prog="run_geometry_certificate_audit") parser.add_argument("--config", required=True, type=Path) parser.add_argument("--output-dir", type=Path) parser.add_argument("--window-count", type=int) args = parser.parse_args(argv) config_path = args.config.resolve() if args.output_dir is None and args.window_count is None: result = run_audit(config_path) else: config = load_audit_config(config_path) config = replace( config, output_dir=str(args.output_dir.resolve()) if args.output_dir else config.output_dir, window_count=args.window_count or config.window_count, permutation_windows=min( config.permutation_windows, args.window_count or config.window_count ), ) temporary_config = Path(config.output_dir).resolve().with_suffix(".resolved.yaml") if temporary_config.exists(): raise FileExistsError(f"refusing to overwrite resolved config: {temporary_config}") temporary_config.parent.mkdir(parents=True, exist_ok=True) temporary_config.write_text( yaml.safe_dump(_config_to_dict(config), sort_keys=False), encoding="utf-8" ) result = run_audit(temporary_config) print(json.dumps({"status": result["status"], "metrics": result["metrics"]}, sort_keys=True)) return 0 def _load_context_rgb_and_cameras( manifest: SceneManifest, frames: Sequence[Any], image_size: tuple[int, int] ) -> tuple[Tensor, Cameras]: if manifest.root is None: raise ValueError("manifest root is required") original_height, original_width = manifest.image_size target_height, target_width = image_size rgb = [] intrinsics = [] poses = [] for frame in frames: image = Image.open(manifest.root / frame.rgb).convert("RGB") if (image.height, image.width) != image_size: image = image.resize((target_width, target_height), Image.Resampling.BICUBIC) rgb.append( torch.from_numpy(np.asarray(image, dtype=np.float32).copy()) .permute(2, 0, 1) .div(255.0) ) matrix = torch.tensor(frame.intrinsics, dtype=torch.float32) matrix[0, 0] *= target_width / original_width matrix[0, 2] *= target_width / original_width matrix[1, 1] *= target_height / original_height matrix[1, 2] *= target_height / original_height intrinsics.append(matrix) poses.append(torch.tensor(frame.c2w, dtype=torch.float32)) cameras = Cameras(torch.stack(intrinsics), torch.stack(poses), image_size) world_to_anchor = torch.linalg.inv(cameras.c2w[0]) return torch.stack(rgb), transform_cameras(cameras, world_to_anchor) def _load_context_depth( manifest: SceneManifest, frames: Sequence[Any], image_size: tuple[int, int] ) -> tuple[Tensor, list[Path]]: if manifest.root is None: raise ValueError("manifest root is required") values = [] paths = [] for frame in frames: if frame.depth is None: raise ValueError("post-hoc certificate audit requires context depth labels") path = (manifest.root / frame.depth).resolve() values.append(torch.from_numpy(np.load(path).astype(np.float32))) paths.append(path) depth = torch.stack(values)[:, None] if depth.shape[-2:] != image_size: depth = functional.interpolate(depth, size=image_size, mode="nearest") return depth[:, 0], paths def _evaluate_window( build: CertificateBuildResult, depths: Tensor, cameras: Cameras, config: GeometryAuditConfig, ) -> dict[str, Any]: errors = [] risks = [] for certificate in build.certificates: error = _certificate_error(certificate, depths, cameras) if error is not None: errors.append(error) risks.append(_certificate_risk(certificate, config.certificate)) raw_confidence_errors = [] for observation in build.raw_observations: error = _raw_observation_error(observation, depths, cameras) if error is not None: raw_confidence_errors.append((observation.proposal_confidence, error)) shuffled_errors = _shuffled_errors(build.certificates, depths, cameras, config) shuffled_cameras = Cameras( cameras.intrinsics, cameras.c2w.roll(shifts=1, dims=0), cameras.image_size, ) camera_shuffled_errors = [] penalty = _bounds_diagonal(config.local_bounds_m) for certificate in build.certificates: result = triangulate_dlt( torch.tensor(certificate.source_xy), torch.tensor(certificate.matched_xy), shuffled_cameras, certificate.source_view, certificate.matched_view, ) if not result.cheirality: camera_shuffled_errors.append(penalty) continue error = _point_error_against_views( result.point, ( (certificate.source_view, certificate.source_xy), (certificate.matched_view, certificate.matched_xy), ), depths, cameras, ) camera_shuffled_errors.append(penalty if error is None else error) voxel_coverage = _voxel_coverage( build.certificates, config.local_bounds_m, config.voxel_resolution ) return { "certificate_count": len(build.certificates), "evaluated_certificate_count": len(errors), "geometry_errors_m": errors, "risks": risks, "raw_confidence_and_errors_m": raw_confidence_errors, "shuffled_errors_m": shuffled_errors, "camera_shuffled_errors_m": camera_shuffled_errors, "geometry_error_median_m": _quantile(errors, 0.5), "geometry_error_p90_m": _quantile(errors, 0.9), "native_voxel_coverage": voxel_coverage, } def _certificate_error( certificate: GeometryCertificate, depths: Tensor, cameras: Cameras ) -> float | None: point = torch.tensor(certificate.point, dtype=torch.float32) return _point_error_against_views( point, ( (certificate.source_view, certificate.source_xy), (certificate.matched_view, certificate.matched_xy), (certificate.verification_view, certificate.verification_xy), ), depths, cameras, ) def _raw_observation_error( observation: RawObservation, depths: Tensor, cameras: Cameras ) -> float | None: if observation.point is None or not observation.cheirality: return None return _point_error_against_views( torch.tensor(observation.point), ( (observation.source_view, observation.source_xy), (observation.matched_view, observation.matched_xy), ), depths, cameras, ) def _point_error_against_views( point: Tensor, observations: Sequence[tuple[int, tuple[float, float]]], depths: Tensor, cameras: Cameras, ) -> float | None: errors = [] for view, xy in observations: truth = _depth_point(depths[view], xy, cameras, view) if truth is None: return None errors.append(float(torch.linalg.vector_norm(point - truth).item())) return max(errors) def _depth_point( depth: Tensor, xy: tuple[float, float], cameras: Cameras, view: int ) -> Tensor | None: x = min(depth.shape[1] - 1, max(0, int(round(xy[0])))) y = min(depth.shape[0] - 1, max(0, int(round(xy[1])))) distance = depth[y, x] if not torch.isfinite(distance) or distance <= 0: return None pixel = torch.tensor([xy[0], xy[1], 1.0], dtype=cameras.dtype) direction = torch.linalg.inv(cameras.intrinsics[view]) @ pixel direction = direction / torch.linalg.vector_norm(direction).clamp_min(1e-8) world_direction = cameras.c2w[view, :3, :3] @ direction return cameras.c2w[view, :3, 3] + world_direction * distance def _shuffled_errors( certificates: Sequence[GeometryCertificate], depths: Tensor, cameras: Cameras, config: GeometryAuditConfig, ) -> list[float]: by_pair: dict[tuple[int, int], list[GeometryCertificate]] = {} for certificate in certificates: by_pair.setdefault((certificate.source_view, certificate.matched_view), []).append( certificate ) penalty = _bounds_diagonal(config.local_bounds_m) errors = [] for (source_view, matched_view), values in by_pair.items(): if len(values) < 2: continue ordered = sorted(values, key=lambda item: (item.source_xy[1], item.source_xy[0])) shifted = ordered[1:] + ordered[:1] for source, wrong_match in zip(ordered, shifted, strict=True): result = triangulate_dlt( torch.tensor(source.source_xy), torch.tensor(wrong_match.matched_xy), cameras, source_view, matched_view, ) if not result.cheirality: errors.append(penalty) continue error = _point_error_against_views( result.point, ( (source_view, source.source_xy), (matched_view, wrong_match.matched_xy), ), depths, cameras, ) errors.append(penalty if error is None else error) return errors def _certificate_risk(certificate: GeometryCertificate, config: CertificateConfig) -> float: components = ( 1.0 - certificate.proposal_confidence, certificate.reciprocal_error_px / config.reciprocal_threshold_px, certificate.cycle_error_px / config.cycle_threshold_px, certificate.epipolar_error_px / config.epipolar_threshold_px, certificate.reprojection_error_px / config.reprojection_threshold_px, certificate.verification_error_px / config.verification_threshold_px, config.min_triangulation_angle_deg / max(certificate.triangulation_angle_deg, config.min_triangulation_angle_deg), ) return float(sum(min(1.0, max(0.0, value)) for value in components) / len(components)) def _matched_confidence_errors( confidence_errors: Sequence[tuple[float, float]], *, target_count: int ) -> list[float]: if target_count <= 0: return [] ranked = sorted(confidence_errors, key=lambda item: (-item[0], item[1])) return [error for _, error in ranked[: min(target_count, len(ranked))]] def _aggregate_metrics( windows: Sequence[dict[str, Any]], *, geometry_errors: Sequence[float], risks: Sequence[float], confidence_errors: Sequence[float], shuffled_errors: Sequence[float], camera_shuffled_errors: Sequence[float], permutation_deltas: Sequence[float], ) -> dict[str, Any]: stage_names = ("raw", "reciprocal", "cycle", "geometric", "certified") stage_totals = { name: sum(int(window["stage_counts"][name]) for window in windows) for name in stage_names } return { "window_count": len(windows), "scene_count": len({window["scene_id"] for window in windows}), "stage_totals": stage_totals, "stage_retention": { name: stage_totals[name] / stage_totals["raw"] if stage_totals["raw"] else 0.0 for name in stage_names }, "certified_coverage_macro": _mean( [float(window["certified_source_coverage"]) for window in windows] ), "nonzero_window_fraction": _mean( [float(window["certificate_count"] > 0) for window in windows] ), "geometry_evaluated_count": len(geometry_errors), "geometry_error_median_m": _quantile(geometry_errors, 0.5), "geometry_error_p90_m": _quantile(geometry_errors, 0.9), "matched_confidence_count": len(confidence_errors), "matched_confidence_median_error_m": _quantile(confidence_errors, 0.5), "shuffled_count": len(shuffled_errors), "shuffled_median_error_m": _quantile(shuffled_errors, 0.5), "camera_shuffled_median_error_m": _quantile(camera_shuffled_errors, 0.5), "permutation_window_count": len(permutation_deltas), "permutation_max_point_delta_m": max(permutation_deltas) if permutation_deltas else None, "native_voxel_coverage_macro": _mean( [float(window["native_voxel_coverage"]) for window in windows] ), "risk_error_spearman": _spearman(risks, geometry_errors), "risk_bin_median_errors_m": _risk_bins(risks, geometry_errors), } def _point_set_delta(first: CertificateBuildResult, second: CertificateBuildResult) -> float: if not first.certificates and not second.certificates: return 0.0 if not first.certificates or not second.certificates: return math.inf points_first = torch.tensor([item.point for item in first.certificates]) points_second = torch.tensor([item.point for item in second.certificates]) maximum = 0.0 for source, target in ((points_first, points_second), (points_second, points_first)): for start in range(0, len(source), 1024): nearest = torch.cdist(source[start : start + 1024], target).amin(dim=1) maximum = max(maximum, float(nearest.max().item())) return maximum def _voxel_coverage( certificates: Sequence[GeometryCertificate], bounds: tuple[tuple[float, float, float], tuple[float, float, float]], resolution: tuple[int, int, int], ) -> float: lower = np.asarray(bounds[0], dtype=np.float64) upper = np.asarray(bounds[1], dtype=np.float64) depth, height, width = resolution occupied = set() for certificate in certificates: point = np.asarray(certificate.point) fraction = (point - lower) / (upper - lower) if np.all((fraction >= 0) & (fraction < 1)): x = min(width - 1, int(fraction[0] * width)) y = min(height - 1, int(fraction[1] * height)) z = min(depth - 1, int(fraction[2] * depth)) occupied.add((z, y, x)) return len(occupied) / (depth * height * width) def _risk_bins(risks: Sequence[float], errors: Sequence[float], bins: int = 4) -> list[float]: if len(risks) != len(errors) or not risks: return [] order = np.argsort(np.asarray(risks), kind="stable") groups = np.array_split(order, bins) return [float(np.median(np.asarray(errors)[group])) for group in groups if len(group)] def _spearman(first: Sequence[float], second: Sequence[float]) -> float | None: if len(first) != len(second) or len(first) < 2: return None rank_first = np.argsort(np.argsort(np.asarray(first), kind="stable"), kind="stable") rank_second = np.argsort(np.argsort(np.asarray(second), kind="stable"), kind="stable") correlation = np.corrcoef(rank_first, rank_second)[0, 1] return float(correlation) if np.isfinite(correlation) else None def _weight_artifacts(root: Path) -> list[dict[str, str]]: if not root.exists(): return [] return [ {"path": str(path.resolve()), "sha256": _sha256(path)} for path in sorted(root.rglob("*.ckpt")) ] def _config_to_dict(config: GeometryAuditConfig) -> dict[str, Any]: return { "seed": config.seed, "dataset_root": config.dataset_root, "output_dir": config.output_dir, "context_views": config.context_views, "image_size": list(config.image_size), "window_count": config.window_count, "window_stride": config.window_stride, "permutation_windows": config.permutation_windows, "local_bounds_m": [list(row) for row in config.local_bounds_m], "voxel_resolution": list(config.voxel_resolution), "certificate": asdict(config.certificate), "decision": asdict(config.decision), } def _stable_hash_int(*values: object) -> int: payload = "|".join(str(value) for value in values).encode("utf-8") return int.from_bytes(hashlib.sha256(payload).digest(), "big") def _pair(value: Any, name: str) -> tuple[int, int]: if not isinstance(value, list) or len(value) != 2: raise ValueError(f"{name} must contain two integers") return int(value[0]), int(value[1]) def _triple(value: Any, name: str) -> tuple[int, int, int]: if not isinstance(value, list) or len(value) != 3: raise ValueError(f"{name} must contain three integers") return int(value[0]), int(value[1]), int(value[2]) def _bounds(value: Any) -> tuple[tuple[float, float, float], tuple[float, float, float]]: if not isinstance(value, list) or len(value) != 2: raise ValueError("local_bounds_m must contain lower and upper vectors") return tuple(tuple(float(item) for item in row) for row in value) # type: ignore[return-value] def _bounds_diagonal( bounds: tuple[tuple[float, float, float], tuple[float, float, float]] ) -> float: return float(np.linalg.norm(np.asarray(bounds[1]) - np.asarray(bounds[0]))) def _quantile(values: Sequence[float], q: float) -> float | None: return float(np.quantile(values, q)) if values else None def _mean(values: Sequence[float]) -> float | None: return float(np.mean(values)) if values else None def _format_metric(value: Any) -> str: if value is None: return "not available" if isinstance(value, float): return f"{value:.6g}" return str(value) def _now() -> str: return datetime.now().astimezone().isoformat(timespec="microseconds") def _sha256(path: Path) -> str: digest = hashlib.sha256() with path.open("rb") as handle: while chunk := handle.read(1024 * 1024): digest.update(chunk) return digest.hexdigest() def _atomic_json(path: Path, payload: Any) -> None: path.parent.mkdir(parents=True, exist_ok=True) temporary = path.with_name(path.name + ".part") temporary.write_text( json.dumps(payload, indent=2, sort_keys=True, allow_nan=False) + "\n", encoding="utf-8" ) os.replace(temporary, path) def _append_jsonl(path: Path, payload: Any) -> None: with path.open("a", encoding="utf-8") as handle: handle.write(json.dumps(payload, sort_keys=True, allow_nan=False) + "\n") if __name__ == "__main__": raise SystemExit(main())