splatthis 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. splatthis/__init__.py +50 -0
  2. splatthis/_version.py +3 -0
  3. splatthis/adaptive_compute.py +520 -0
  4. splatthis/artifact_backends.py +556 -0
  5. splatthis/artifact_evaluation.py +126 -0
  6. splatthis/artifact_gates.py +368 -0
  7. splatthis/artifact_io.py +45 -0
  8. splatthis/browser_capture.py +815 -0
  9. splatthis/browser_export.py +426 -0
  10. splatthis/budgets.py +338 -0
  11. splatthis/canvas_parity.py +107 -0
  12. splatthis/cli.py +721 -0
  13. splatthis/color.py +50 -0
  14. splatthis/config.py +214 -0
  15. splatthis/conversion_engine.py +125 -0
  16. splatthis/converter.py +12 -0
  17. splatthis/distillation.py +608 -0
  18. splatthis/domain.py +82 -0
  19. splatthis/engine_artifacts.py +379 -0
  20. splatthis/engine_configuration.py +891 -0
  21. splatthis/engine_densification.py +769 -0
  22. splatthis/engine_guidance.py +702 -0
  23. splatthis/engine_initialization.py +511 -0
  24. splatthis/engine_optimization.py +857 -0
  25. splatthis/engine_postfit.py +887 -0
  26. splatthis/engine_state.py +285 -0
  27. splatthis/export_common.py +388 -0
  28. splatthis/features.py +492 -0
  29. splatthis/fidelity/__init__.py +32 -0
  30. splatthis/fidelity/analysis.py +101 -0
  31. splatthis/fidelity/config.py +66 -0
  32. splatthis/fidelity/evaluator.py +183 -0
  33. splatthis/fidelity/metrics.py +244 -0
  34. splatthis/fidelity/operators.py +97 -0
  35. splatthis/fidelity/report.py +43 -0
  36. splatthis/fidelity/stage.py +176 -0
  37. splatthis/io.py +132 -0
  38. splatthis/mixed_primitives.py +447 -0
  39. splatthis/mlx_losses.py +252 -0
  40. splatthis/mlx_optimizer.py +176 -0
  41. splatthis/mlx_renderer.py +537 -0
  42. splatthis/mlx_runtime.py +56 -0
  43. splatthis/mlx_stage.py +504 -0
  44. splatthis/optimizer.py +131 -0
  45. splatthis/pipeline.py +95 -0
  46. splatthis/pipeline_artifacts.py +335 -0
  47. splatthis/pipeline_phases.py +442 -0
  48. splatthis/pixel_runtime.py +987 -0
  49. splatthis/pptx_export.py +745 -0
  50. splatthis/profiles.py +365 -0
  51. splatthis/proxies.py +165 -0
  52. splatthis/py.typed +0 -0
  53. splatthis/quality.py +76 -0
  54. splatthis/renderer.py +1428 -0
  55. splatthis/reporting.py +72 -0
  56. splatthis/roundtrip.py +84 -0
  57. splatthis/splat.py +549 -0
  58. splatthis/storage.py +202 -0
  59. splatthis/svg_export.py +1106 -0
  60. splatthis/svg_recipe_gate.py +236 -0
  61. splatthis/template_assets.py +36 -0
  62. splatthis/templates/__init__.py +1 -0
  63. splatthis/templates/drawingml/background_shape.xml +31 -0
  64. splatthis/templates/drawingml/blur.xml +1 -0
  65. splatthis/templates/drawingml/close_group.xml +1 -0
  66. splatthis/templates/drawingml/edge_segment.xml +21 -0
  67. splatthis/templates/drawingml/effect_list.xml +3 -0
  68. splatthis/templates/drawingml/gradient_fill.xml +7 -0
  69. splatthis/templates/drawingml/gradient_stop.xml +3 -0
  70. splatthis/templates/drawingml/group.xml +14 -0
  71. splatthis/templates/drawingml/shape.xml +30 -0
  72. splatthis/templates/drawingml/shape_no_effect.xml +29 -0
  73. splatthis/templates/drawingml/slide.xml +24 -0
  74. splatthis/templates/drawingml/soft_edge.xml +1 -0
  75. splatthis/templates/drawingml/solid_fill.xml +3 -0
  76. splatthis/templates/pptx/app_props.xml +7 -0
  77. splatthis/templates/pptx/content_types.xml +15 -0
  78. splatthis/templates/pptx/core_props.xml +12 -0
  79. splatthis/templates/pptx/pres_props.xml +4 -0
  80. splatthis/templates/pptx/presentation.xml +14 -0
  81. splatthis/templates/pptx/presentation_rels.xml +8 -0
  82. splatthis/templates/pptx/raster_slide.xml +49 -0
  83. splatthis/templates/pptx/raster_slide_rels.xml +5 -0
  84. splatthis/templates/pptx/root_rels.xml +6 -0
  85. splatthis/templates/pptx/slide_layout.xml +26 -0
  86. splatthis/templates/pptx/slide_layout_rels.xml +4 -0
  87. splatthis/templates/pptx/slide_master.xml +39 -0
  88. splatthis/templates/pptx/slide_master_rels.xml +5 -0
  89. splatthis/templates/pptx/theme.xml +55 -0
  90. splatthis/templates/pptx/vector_slide_rels.xml +4 -0
  91. splatthis/templates/pptx/view_props.xml +4 -0
  92. splatthis/templates/reporting/side_by_side.html +45 -0
  93. splatthis/templates/svg/background.svg +1 -0
  94. splatthis/templates/svg/blur_document.svg +7 -0
  95. splatthis/templates/svg/blur_ellipse.svg +1 -0
  96. splatthis/templates/svg/blur_filter.svg +3 -0
  97. splatthis/templates/svg/close.svg +1 -0
  98. splatthis/templates/svg/edge_group.svg +2 -0
  99. splatthis/templates/svg/edge_line.svg +1 -0
  100. splatthis/templates/svg/edge_path.svg +1 -0
  101. splatthis/templates/svg/ellipse.svg +1 -0
  102. splatthis/templates/svg/empty_document.svg +3 -0
  103. splatthis/templates/svg/palette_background.svg +1 -0
  104. splatthis/templates/svg/palette_document.svg +9 -0
  105. splatthis/templates/svg/palette_ellipse.svg +1 -0
  106. splatthis/templates/svg/palette_gradient.svg +3 -0
  107. splatthis/templates/svg/palette_stop.svg +1 -0
  108. splatthis/templates/svg/scripted_document.svg +9 -0
  109. splatthis/templates/svg/scripted_runtime.js +52 -0
  110. splatthis/templates/svg/standard_document.svg +12 -0
  111. splatthis/templates/svg/standard_gradient.svg +3 -0
  112. splatthis/templates/svg/standard_stop.svg +1 -0
  113. splatthis-0.2.0.dist-info/METADATA +455 -0
  114. splatthis-0.2.0.dist-info/RECORD +118 -0
  115. splatthis-0.2.0.dist-info/WHEEL +5 -0
  116. splatthis-0.2.0.dist-info/entry_points.txt +2 -0
  117. splatthis-0.2.0.dist-info/licenses/LICENSE +21 -0
  118. splatthis-0.2.0.dist-info/top_level.txt +1 -0
splatthis/__init__.py ADDED
@@ -0,0 +1,50 @@
1
+ """Target-aware 2D Gaussian splat conversion and browser runtimes."""
2
+
3
+ from ._version import __version__
4
+ from .artifact_evaluation import (
5
+ evaluate_css_export_quality,
6
+ evaluate_native_canvas_export_quality,
7
+ evaluate_svg_export_quality,
8
+ )
9
+ from .browser_export import generate_css_splat_html, generate_native_canvas_html
10
+ from .config import ConversionRequest, ConverterConfig
11
+ from .converter import PNG2SVGConverter
12
+ from .domain import EvidenceLevel, SplatScene
13
+ from .pixel_runtime import (
14
+ generate_parallax_pixel_runtime_html,
15
+ generate_pixel_runtime_html,
16
+ generate_webgl_pixel_runtime_html,
17
+ )
18
+ from .pptx_export import save_pptx_with_splat_png, save_pptx_with_splats
19
+ from .reporting import save_side_by_side_html
20
+ from .roundtrip import validate_export_roundtrip
21
+ from .splat import GaussianSplat, RawSplat
22
+ from .storage import load_png, load_splats_json, render_splats_preview_png
23
+ from .svg_export import save_svg
24
+
25
+ __all__ = [
26
+ "__version__",
27
+ "GaussianSplat",
28
+ "RawSplat",
29
+ "SplatScene",
30
+ "EvidenceLevel",
31
+ "ConversionRequest",
32
+ "ConverterConfig",
33
+ "load_png",
34
+ "save_svg",
35
+ "save_pptx_with_splats",
36
+ "save_pptx_with_splat_png",
37
+ "load_splats_json",
38
+ "render_splats_preview_png",
39
+ "save_side_by_side_html",
40
+ "generate_css_splat_html",
41
+ "generate_native_canvas_html",
42
+ "generate_pixel_runtime_html",
43
+ "generate_webgl_pixel_runtime_html",
44
+ "generate_parallax_pixel_runtime_html",
45
+ "evaluate_css_export_quality",
46
+ "evaluate_native_canvas_export_quality",
47
+ "evaluate_svg_export_quality",
48
+ "validate_export_roundtrip",
49
+ "PNG2SVGConverter",
50
+ ]
splatthis/_version.py ADDED
@@ -0,0 +1,3 @@
1
+ """Single source of truth for the public package version."""
2
+
3
+ __version__ = "0.2.0"
@@ -0,0 +1,520 @@
1
+ """Canvas adaptive-compute policies.
2
+
3
+ The online controller stops only on an absolute target observed in the current
4
+ run. The retrospective helpers can measure whether broader stopping or scaling
5
+ rules would have saved work, but do not predict an unseen 4k or 8k result.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+ from typing import Any, Dict, Mapping, Optional, Sequence, Tuple
12
+
13
+ # Full-frame model-to-Chrome calibration, data/canvas-checkpoint-parity.json.
14
+ DEFAULT_CHROME_SSIM_SAFETY_MARGIN = 0.0
15
+ DEFAULT_CHROME_PSNR_SAFETY_MARGIN = 0.0
16
+ CANVAS_RUNTIME_SCORER = "canvas-image-data-byte-v1"
17
+ CANVAS_RUNTIME_CALIBRATION_CHECKPOINTS = 48
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class CanvasCheckpoint:
22
+ label: str
23
+ ssim_srgb: float
24
+ psnr_srgb: float
25
+ splat_count: int
26
+ elapsed_sec: float
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class AdaptiveComputePolicy:
31
+ """Policy parameters for replaying an observed checkpoint curve."""
32
+
33
+ min_checkpoints: int = 2
34
+ target_ssim_srgb: Optional[float] = 0.98
35
+ target_psnr_srgb: Optional[float] = None
36
+ checkpoint_min_ssim_gain: float = 0.0005
37
+ max_ssim_regression: float = 0.0005
38
+ max_psnr_regression: float = 0.10
39
+ plateau_min_ssim_gain: float = 0.002
40
+ plateau_min_psnr_gain: float = 0.10
41
+ min_ssim_gain_per_second: float = 0.0
42
+ stop_on_regression: bool = True
43
+ stop_on_plateau: bool = True
44
+
45
+ def __post_init__(self) -> None:
46
+ if self.min_checkpoints < 1:
47
+ raise ValueError("min_checkpoints must be positive")
48
+ for name in (
49
+ "checkpoint_min_ssim_gain",
50
+ "max_ssim_regression",
51
+ "max_psnr_regression",
52
+ "plateau_min_ssim_gain",
53
+ "plateau_min_psnr_gain",
54
+ "min_ssim_gain_per_second",
55
+ ):
56
+ if float(getattr(self, name)) < 0.0:
57
+ raise ValueError(f"{name} must be non-negative")
58
+
59
+
60
+ @dataclass(frozen=True)
61
+ class OnlineAdaptiveConfig:
62
+ """Conservative online policy that only stops on an absolute quality target.
63
+
64
+ Plateau, regression, and higher-budget prediction remain retrospective
65
+ experiments. The online controller sees only completed pixel-runtime checkpoints
66
+ and cannot use a future result to justify a stop.
67
+ """
68
+
69
+ enabled: bool = False
70
+ min_checkpoints: int = 2
71
+ target_ssim_srgb: Optional[float] = 0.98
72
+ target_psnr_srgb: Optional[float] = None
73
+ chrome_ssim_safety_margin: float = DEFAULT_CHROME_SSIM_SAFETY_MARGIN
74
+ chrome_psnr_safety_margin: float = DEFAULT_CHROME_PSNR_SAFETY_MARGIN
75
+ checkpoint_min_ssim_gain: float = 0.0005
76
+ max_ssim_regression: float = 0.0005
77
+ max_psnr_regression: float = 0.10
78
+
79
+ def __post_init__(self) -> None:
80
+ if self.min_checkpoints < 1:
81
+ raise ValueError("adaptive_compute_min_checkpoints must be positive")
82
+ if self.target_ssim_srgb is not None and not (
83
+ 0.0 <= self.target_ssim_srgb <= 1.0
84
+ ):
85
+ raise ValueError(
86
+ "adaptive_compute_target_ssim_srgb must be between 0 and 1"
87
+ )
88
+ if self.target_psnr_srgb is not None and self.target_psnr_srgb < 0.0:
89
+ raise ValueError("adaptive_compute_target_psnr_srgb must be non-negative")
90
+ if self.chrome_ssim_safety_margin < 0.0:
91
+ raise ValueError("adaptive_compute_chrome_ssim_margin must be non-negative")
92
+ if self.chrome_psnr_safety_margin < 0.0:
93
+ raise ValueError("adaptive_compute_chrome_psnr_margin must be non-negative")
94
+ for name in (
95
+ "checkpoint_min_ssim_gain",
96
+ "max_ssim_regression",
97
+ "max_psnr_regression",
98
+ ):
99
+ if float(getattr(self, name)) < 0.0:
100
+ raise ValueError(f"{name} must be non-negative")
101
+ if (
102
+ self.enabled
103
+ and self.target_ssim_srgb is None
104
+ and self.target_psnr_srgb is None
105
+ ):
106
+ raise ValueError("adaptive compute requires an SSIM or PSNR quality target")
107
+ if (
108
+ self.enabled
109
+ and self.effective_model_ssim_threshold is not None
110
+ and self.effective_model_ssim_threshold > 1.0
111
+ ):
112
+ raise ValueError(
113
+ "adaptive SSIM target plus Chrome safety margin must not exceed 1"
114
+ )
115
+
116
+ @property
117
+ def effective_model_ssim_threshold(self) -> Optional[float]:
118
+ if self.target_ssim_srgb is None:
119
+ return None
120
+ return float(self.target_ssim_srgb + self.chrome_ssim_safety_margin)
121
+
122
+ @property
123
+ def effective_model_psnr_threshold(self) -> Optional[float]:
124
+ if self.target_psnr_srgb is None:
125
+ return None
126
+ return float(self.target_psnr_srgb + self.chrome_psnr_safety_margin)
127
+
128
+ def checkpoint_policy(self) -> AdaptiveComputePolicy:
129
+ """Return the shared checkpoint-selection policy used by the converter."""
130
+
131
+ return AdaptiveComputePolicy(
132
+ min_checkpoints=self.min_checkpoints,
133
+ target_ssim_srgb=self.target_ssim_srgb,
134
+ target_psnr_srgb=self.target_psnr_srgb,
135
+ checkpoint_min_ssim_gain=self.checkpoint_min_ssim_gain,
136
+ max_ssim_regression=self.max_ssim_regression,
137
+ max_psnr_regression=self.max_psnr_regression,
138
+ plateau_min_ssim_gain=0.0,
139
+ plateau_min_psnr_gain=0.0,
140
+ min_ssim_gain_per_second=0.0,
141
+ stop_on_regression=False,
142
+ stop_on_plateau=False,
143
+ )
144
+
145
+ def as_dict(self) -> Dict[str, Any]:
146
+ return {
147
+ **self.__dict__,
148
+ "effective_model_ssim_threshold": self.effective_model_ssim_threshold,
149
+ "effective_model_psnr_threshold": self.effective_model_psnr_threshold,
150
+ "runtime_scorer": CANVAS_RUNTIME_SCORER,
151
+ "runtime_scorer_pixel_exact": True,
152
+ "runtime_scorer_calibration_checkpoints": (
153
+ CANVAS_RUNTIME_CALIBRATION_CHECKPOINTS
154
+ ),
155
+ "runtime_scorer_calibration": "data/canvas-checkpoint-parity.json",
156
+ }
157
+
158
+
159
+ @dataclass(frozen=True)
160
+ class OnlineAdaptiveDecision:
161
+ """Decision made from the pixel-runtime checkpoints observed so far."""
162
+
163
+ stop: bool
164
+ reason: str
165
+ checkpoints_observed: int
166
+ current: CanvasCheckpoint
167
+ selected: CanvasCheckpoint
168
+ config: OnlineAdaptiveConfig
169
+
170
+ def as_dict(self) -> Dict[str, Any]:
171
+ return {
172
+ "mode": "online-observed-only",
173
+ "uses_future_evidence": False,
174
+ "stop": self.stop,
175
+ "reason": self.reason,
176
+ "checkpoints_observed": self.checkpoints_observed,
177
+ "current": dict(self.current.__dict__),
178
+ "selected": dict(self.selected.__dict__),
179
+ "requested_chrome_target": {
180
+ "ssim_srgb": self.config.target_ssim_srgb,
181
+ "psnr_srgb": self.config.target_psnr_srgb,
182
+ },
183
+ "effective_model_threshold": {
184
+ "ssim_srgb": self.config.effective_model_ssim_threshold,
185
+ "psnr_srgb": self.config.effective_model_psnr_threshold,
186
+ },
187
+ "policy": self.config.as_dict(),
188
+ }
189
+
190
+
191
+ @dataclass(frozen=True)
192
+ class AdaptiveSimulationResult:
193
+ selected: CanvasCheckpoint
194
+ stop_checkpoint: CanvasCheckpoint
195
+ full_run_best: CanvasCheckpoint
196
+ stop_reason: str
197
+ checkpoints_observed: int
198
+ checkpoints_available: int
199
+ observed_stage_sec: float
200
+ full_stage_sec: float
201
+ saved_stage_sec: float
202
+ ssim_opportunity_cost: float
203
+ psnr_opportunity_cost: float
204
+ decisions: Tuple[Dict[str, Any], ...]
205
+
206
+ def as_dict(self) -> Dict[str, Any]:
207
+ return {
208
+ "selected": dict(self.selected.__dict__),
209
+ "stop_checkpoint": dict(self.stop_checkpoint.__dict__),
210
+ "full_run_best": dict(self.full_run_best.__dict__),
211
+ "stop_reason": self.stop_reason,
212
+ "checkpoints_observed": self.checkpoints_observed,
213
+ "checkpoints_available": self.checkpoints_available,
214
+ "observed_stage_sec": self.observed_stage_sec,
215
+ "full_stage_sec": self.full_stage_sec,
216
+ "saved_stage_sec": self.saved_stage_sec,
217
+ "ssim_opportunity_cost": self.ssim_opportunity_cost,
218
+ "psnr_opportunity_cost": self.psnr_opportunity_cost,
219
+ "decisions": list(self.decisions),
220
+ }
221
+
222
+
223
+ @dataclass(frozen=True)
224
+ class CanvasBudgetPoint:
225
+ image: str
226
+ requested_budget: int
227
+ ssim_srgb: float
228
+ lpips: float
229
+ runtime_sec: float
230
+ artifact_bytes: int
231
+ final_splats: int
232
+
233
+
234
+ @dataclass(frozen=True)
235
+ class ScalingPolicy:
236
+ """Retrospective 2k-to-4k scale decision thresholds."""
237
+
238
+ target_ssim_srgb: float = 0.95
239
+ target_lpips: Optional[float] = 0.15
240
+ min_ssim_gain: float = 0.005
241
+ min_lpips_gain: float = 0.001
242
+
243
+
244
+ def resolve_online_adaptive_config(
245
+ refinement_config: Mapping[str, Any],
246
+ ) -> OnlineAdaptiveConfig:
247
+ """Resolve and validate the converter's default-off online policy."""
248
+
249
+ enabled_value = refinement_config.get("adaptive_compute_enabled", False)
250
+ if not isinstance(enabled_value, bool):
251
+ raise ValueError("adaptive_compute_enabled must be a boolean")
252
+ target_ssim = refinement_config.get("adaptive_compute_target_ssim_srgb", 0.98)
253
+ target_psnr = refinement_config.get("adaptive_compute_target_psnr_srgb")
254
+ return OnlineAdaptiveConfig(
255
+ enabled=enabled_value,
256
+ min_checkpoints=int(
257
+ refinement_config.get("adaptive_compute_min_checkpoints", 2)
258
+ ),
259
+ target_ssim_srgb=(None if target_ssim is None else float(target_ssim)),
260
+ target_psnr_srgb=(None if target_psnr is None else float(target_psnr)),
261
+ chrome_ssim_safety_margin=float(
262
+ refinement_config.get(
263
+ "adaptive_compute_chrome_ssim_margin",
264
+ DEFAULT_CHROME_SSIM_SAFETY_MARGIN,
265
+ )
266
+ ),
267
+ chrome_psnr_safety_margin=float(
268
+ refinement_config.get(
269
+ "adaptive_compute_chrome_psnr_margin",
270
+ DEFAULT_CHROME_PSNR_SAFETY_MARGIN,
271
+ )
272
+ ),
273
+ checkpoint_min_ssim_gain=float(
274
+ refinement_config.get("canvas_stage_min_ssim_gain", 0.0005)
275
+ ),
276
+ max_ssim_regression=float(
277
+ refinement_config.get("canvas_stage_max_ssim_regression", 0.0005)
278
+ ),
279
+ max_psnr_regression=float(
280
+ refinement_config.get("canvas_stage_max_psnr_regression", 0.10)
281
+ ),
282
+ )
283
+
284
+
285
+ def evaluate_online_checkpoints(
286
+ checkpoints: Sequence[CanvasCheckpoint],
287
+ config: OnlineAdaptiveConfig,
288
+ ) -> OnlineAdaptiveDecision:
289
+ """Stop only when an observed, selected checkpoint meets the hard target."""
290
+
291
+ if not checkpoints:
292
+ raise ValueError("at least one checkpoint is required")
293
+ policy = config.checkpoint_policy()
294
+ selected = _best_checkpoint(checkpoints, policy)
295
+ if not config.enabled:
296
+ reason = "disabled"
297
+ stop = False
298
+ elif len(checkpoints) < config.min_checkpoints:
299
+ reason = "minimum-checkpoints"
300
+ stop = False
301
+ else:
302
+ ssim_met = (
303
+ config.effective_model_ssim_threshold is None
304
+ or selected.ssim_srgb >= config.effective_model_ssim_threshold
305
+ )
306
+ psnr_met = (
307
+ config.effective_model_psnr_threshold is None
308
+ or selected.psnr_srgb >= config.effective_model_psnr_threshold
309
+ )
310
+ stop = bool(ssim_met and psnr_met)
311
+ reason = "quality-target" if stop else "quality-target-not-met"
312
+ return OnlineAdaptiveDecision(
313
+ stop=stop,
314
+ reason=reason,
315
+ checkpoints_observed=len(checkpoints),
316
+ current=checkpoints[-1],
317
+ selected=selected,
318
+ config=config,
319
+ )
320
+
321
+
322
+ def simulate_adaptive_checkpoints(
323
+ checkpoints: Sequence[CanvasCheckpoint],
324
+ policy: AdaptiveComputePolicy,
325
+ ) -> AdaptiveSimulationResult:
326
+ """Replay a policy over observed checkpoints and report saved stage work."""
327
+
328
+ if not checkpoints:
329
+ raise ValueError("at least one checkpoint is required")
330
+ for checkpoint in checkpoints:
331
+ if checkpoint.elapsed_sec < 0.0:
332
+ raise ValueError("checkpoint elapsed_sec must be non-negative")
333
+
334
+ full_run_best = _best_checkpoint(checkpoints, policy)
335
+ best = checkpoints[0]
336
+ stop_checkpoint = checkpoints[-1]
337
+ stop_reason = "curve-exhausted"
338
+ observed = len(checkpoints)
339
+ decisions = []
340
+
341
+ for index, checkpoint in enumerate(checkpoints):
342
+ accepted, reason = _prefer_checkpoint(checkpoint, best, policy)
343
+ previous_best = best
344
+ if index == 0 or accepted:
345
+ best = checkpoint
346
+ ssim_gain = checkpoint.ssim_srgb - previous_best.ssim_srgb
347
+ psnr_gain = checkpoint.psnr_srgb - previous_best.psnr_srgb
348
+ gain_rate = (
349
+ ssim_gain / checkpoint.elapsed_sec if checkpoint.elapsed_sec > 0.0 else 0.0
350
+ )
351
+ decision = {
352
+ "index": index,
353
+ "checkpoint": checkpoint.label,
354
+ "accepted": bool(index == 0 or accepted),
355
+ "accept_reason": "initial" if index == 0 else reason,
356
+ "selected": best.label,
357
+ "ssim_gain_vs_previous_best": float(ssim_gain),
358
+ "psnr_gain_vs_previous_best": float(psnr_gain),
359
+ "ssim_gain_per_second": float(gain_rate),
360
+ "stop": False,
361
+ "stop_reason": None,
362
+ }
363
+ decisions.append(decision)
364
+
365
+ seen = index + 1
366
+ if seen < policy.min_checkpoints:
367
+ continue
368
+ reason_to_stop = _stop_reason(
369
+ checkpoint=checkpoint,
370
+ selected=best,
371
+ accepted=bool(index == 0 or accepted),
372
+ ssim_gain=ssim_gain,
373
+ psnr_gain=psnr_gain,
374
+ gain_rate=gain_rate,
375
+ policy=policy,
376
+ )
377
+ if reason_to_stop is not None:
378
+ stop_checkpoint = checkpoint
379
+ stop_reason = reason_to_stop
380
+ observed = seen
381
+ decisions[-1]["stop"] = True
382
+ decisions[-1]["stop_reason"] = reason_to_stop
383
+ break
384
+
385
+ observed_seconds = float(
386
+ sum(checkpoint.elapsed_sec for checkpoint in checkpoints[:observed])
387
+ )
388
+ full_seconds = float(sum(checkpoint.elapsed_sec for checkpoint in checkpoints))
389
+ return AdaptiveSimulationResult(
390
+ selected=best,
391
+ stop_checkpoint=stop_checkpoint,
392
+ full_run_best=full_run_best,
393
+ stop_reason=stop_reason,
394
+ checkpoints_observed=observed,
395
+ checkpoints_available=len(checkpoints),
396
+ observed_stage_sec=observed_seconds,
397
+ full_stage_sec=full_seconds,
398
+ saved_stage_sec=max(0.0, full_seconds - observed_seconds),
399
+ ssim_opportunity_cost=max(0.0, full_run_best.ssim_srgb - best.ssim_srgb),
400
+ psnr_opportunity_cost=max(0.0, full_run_best.psnr_srgb - best.psnr_srgb),
401
+ decisions=tuple(decisions),
402
+ )
403
+
404
+
405
+ def retrospective_scale_decision(
406
+ lower: CanvasBudgetPoint,
407
+ higher: CanvasBudgetPoint,
408
+ policy: ScalingPolicy,
409
+ ) -> Dict[str, Any]:
410
+ """Describe an oracle 2k-to-4k decision from two already-observed points."""
411
+
412
+ if lower.image != higher.image:
413
+ raise ValueError("budget points must describe the same image")
414
+ if lower.requested_budget >= higher.requested_budget:
415
+ raise ValueError("higher budget point must have a larger requested budget")
416
+
417
+ ssim_gain = float(higher.ssim_srgb - lower.ssim_srgb)
418
+ lpips_gain = float(lower.lpips - higher.lpips)
419
+ quality_target_met = lower.ssim_srgb >= policy.target_ssim_srgb and (
420
+ policy.target_lpips is None or lower.lpips <= policy.target_lpips
421
+ )
422
+ if quality_target_met:
423
+ scale = False
424
+ reason = "quality-target"
425
+ elif ssim_gain >= policy.min_ssim_gain and lpips_gain >= policy.min_lpips_gain:
426
+ scale = True
427
+ reason = "observed-quality-gain"
428
+ else:
429
+ scale = False
430
+ reason = "observed-gain-below-threshold"
431
+ return {
432
+ "image": lower.image,
433
+ "mode": "retrospective-oracle",
434
+ "from_budget": lower.requested_budget,
435
+ "to_budget": higher.requested_budget,
436
+ "scale": scale,
437
+ "reason": reason,
438
+ "ssim_gain": ssim_gain,
439
+ "lpips_gain": lpips_gain,
440
+ "runtime_delta_sec": float(higher.runtime_sec - lower.runtime_sec),
441
+ "artifact_delta_bytes": int(higher.artifact_bytes - lower.artifact_bytes),
442
+ "final_splat_delta": int(higher.final_splats - lower.final_splats),
443
+ }
444
+
445
+
446
+ def _best_checkpoint(
447
+ checkpoints: Sequence[CanvasCheckpoint],
448
+ policy: AdaptiveComputePolicy,
449
+ ) -> CanvasCheckpoint:
450
+ best = checkpoints[0]
451
+ for checkpoint in checkpoints[1:]:
452
+ accepted, _ = _prefer_checkpoint(checkpoint, best, policy)
453
+ if accepted:
454
+ best = checkpoint
455
+ return best
456
+
457
+
458
+ def _prefer_checkpoint(
459
+ candidate: CanvasCheckpoint,
460
+ incumbent: CanvasCheckpoint,
461
+ policy: AdaptiveComputePolicy,
462
+ ) -> Tuple[bool, str]:
463
+ psnr_safe = candidate.psnr_srgb >= incumbent.psnr_srgb - policy.max_psnr_regression
464
+ if candidate.ssim_srgb >= incumbent.ssim_srgb + policy.checkpoint_min_ssim_gain:
465
+ return (psnr_safe, "material-ssim-gain" if psnr_safe else "psnr-gate")
466
+ if (
467
+ candidate.splat_count < incumbent.splat_count
468
+ and candidate.ssim_srgb >= incumbent.ssim_srgb - policy.max_ssim_regression
469
+ and psnr_safe
470
+ ):
471
+ return True, "smaller-equivalent"
472
+ if candidate.ssim_srgb < incumbent.ssim_srgb - policy.max_ssim_regression:
473
+ return False, "ssim-regression"
474
+ if not psnr_safe:
475
+ return False, "psnr-regression"
476
+ return False, "gain-below-checkpoint-threshold"
477
+
478
+
479
+ def _stop_reason(
480
+ *,
481
+ checkpoint: CanvasCheckpoint,
482
+ selected: CanvasCheckpoint,
483
+ accepted: bool,
484
+ ssim_gain: float,
485
+ psnr_gain: float,
486
+ gain_rate: float,
487
+ policy: AdaptiveComputePolicy,
488
+ ) -> Optional[str]:
489
+ target_ssim_met = (
490
+ policy.target_ssim_srgb is None or selected.ssim_srgb >= policy.target_ssim_srgb
491
+ )
492
+ target_psnr_met = (
493
+ policy.target_psnr_srgb is None or selected.psnr_srgb >= policy.target_psnr_srgb
494
+ )
495
+ target_enabled = (
496
+ policy.target_ssim_srgb is not None or policy.target_psnr_srgb is not None
497
+ )
498
+ if target_enabled and target_ssim_met and target_psnr_met:
499
+ return "quality-target"
500
+ if (
501
+ policy.stop_on_regression
502
+ and not accepted
503
+ and (
504
+ checkpoint.ssim_srgb < selected.ssim_srgb - policy.max_ssim_regression
505
+ or checkpoint.psnr_srgb < selected.psnr_srgb - policy.max_psnr_regression
506
+ )
507
+ ):
508
+ return "regression-revert"
509
+ if (
510
+ policy.stop_on_plateau
511
+ and ssim_gain < policy.plateau_min_ssim_gain
512
+ and psnr_gain < policy.plateau_min_psnr_gain
513
+ ):
514
+ return "plateau"
515
+ if (
516
+ policy.min_ssim_gain_per_second > 0.0
517
+ and gain_rate < policy.min_ssim_gain_per_second
518
+ ):
519
+ return "low-marginal-return"
520
+ return None