#!/usr/bin/env python3 """Record an official eight-level TripoSplat octree trajectory. The fixture keeps the neural and host-controlled parts separate. Every occupancy logit comes from the untouched upstream decoder. The script also records the uniform variate assigned to each parent by upstream ``sample_probs`` and the final per-point voxel jitter, so the browser TypeScript sampler can replay the exact data-dependent trajectory without depending on PyTorch's random-number generator. """ from __future__ import annotations import argparse import hashlib import json import os import sys import time from pathlib import Path from typing import Any from decoder_onnx_common import ( COND_SHAPE, OFFICIAL_REPOSITORY_URL, TOKEN_COUNT, choose_torch_device, load_official_decoder, resolved_file, sha256, source_commit, synchronize_torch, ) def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( "--triposplat-repo", type=Path, required=True, help=f"Local clone of {OFFICIAL_REPOSITORY_URL}.", ) parser.add_argument("--weights", type=Path, required=True) parser.add_argument( "--condition", type=Path, required=True, help="Raw little-endian float32 latent with shape (1,8192,16).", ) parser.add_argument("--output-fixture-dir", type=Path, required=True) parser.add_argument("--device", choices=("cpu", "mps", "cuda", "auto"), default="auto") parser.add_argument("--internal-precision", choices=("fp16", "fp32"), default="fp32") parser.add_argument("--seed", type=int, default=20260715) parser.add_argument("--levels", type=int, default=8) parser.add_argument("--num-points", type=int, default=TOKEN_COUNT) parser.add_argument("--temperature", type=float, default=1.0) args = parser.parse_args() if args.levels < 1 or args.levels > 8: parser.error("--levels must be in [1, 8]") if args.num_points <= 0 or args.num_points > TOKEN_COUNT: parser.error(f"--num-points must be in [1, {TOKEN_COUNT}]") if args.temperature <= 0: parser.error("--temperature must be positive") return args def write_array(np: Any, path: Path, value: Any, dtype: str) -> dict[str, Any]: array = np.ascontiguousarray(value, dtype=dtype) array.tofile(path) return { "path": path.name, "shape": list(array.shape), "dtype": str(array.dtype), "bytes": path.stat().st_size, "sha256": sha256(path), } def hard_link(source: Path, destination: Path) -> None: destination.parent.mkdir(parents=True, exist_ok=True) if destination.exists(): if os.path.samefile(source, destination): return destination.unlink() os.link(source, destination) def main() -> None: try: import numpy as np import torch except ImportError as exc: raise SystemExit(f"PyTorch and NumPy are required: {exc}") from exc args = parse_args() repo = args.triposplat_repo.expanduser().resolve() weights = resolved_file(args.weights, "TripoSplat decoder checkpoint") condition_path = resolved_file(args.condition, "octree condition latent") output_dir = args.output_fixture_dir.expanduser().resolve() output_dir.mkdir(parents=True, exist_ok=True) condition_array = np.fromfile(condition_path, dtype=" Any: value = original_rand(*rand_args, **rand_kwargs) pending_rand_calls.append(value.detach().clone()) return value def recording_rand_like(*rand_args: Any, **rand_kwargs: Any) -> Any: value = original_rand_like(*rand_args, **rand_kwargs) final_jitter_calls.append(value.detach().clone()) return value def recording_sample_probs(probs: Any, counts: Any, algo: str = "systematic") -> Any: call_start = len(pending_rand_calls) sampled = official_sample_probs(probs, counts, algo=algo) calls = pending_rand_calls[call_start:] flat_counts = counts.detach().reshape(-1).to(dtype=torch.long) unique_counts, inverse = flat_counts.unique(sorted=False, return_inverse=True) parent_uniforms = torch.zeros_like(flat_counts, dtype=torch.float32) call_index = 0 group_order: list[int] = [] for index, count in enumerate(unique_counts.tolist()): if count == 0: continue rows = (inverse == index).nonzero(as_tuple=False).squeeze(1) if call_index >= len(calls): raise RuntimeError("Official sample_probs made fewer torch.rand calls than expected") raw = calls[call_index].reshape(-1).to(parent_uniforms.device, dtype=torch.float32) if raw.numel() != rows.numel(): raise RuntimeError( f"Random call {call_index} has {raw.numel()} values for {rows.numel()} rows" ) parent_uniforms.index_copy_(0, rows, raw) group_order.append(int(count)) call_index += 1 if call_index != len(calls): raise RuntimeError("Official sample_probs made unexpected extra torch.rand calls") level_records.append( { "counts": counts.detach().clone(), "sampled": sampled.detach().clone(), "parent_uniforms": parent_uniforms.reshape(counts.shape).detach().clone(), "count_group_order": group_order, } ) return sampled class RecordingOccupancy: def __call__(self, x: Any, resolution: Any, cond: Any, num_points: Any) -> Any: del num_points result = decoder.octree(x, resolution, cond) neural_records.append( { "x": x.detach().clone(), "resolution": resolution.detach().clone(), "logits": result["logits"].detach().clone(), } ) return result torch.manual_seed(args.seed) torch.rand = recording_rand torch.rand_like = recording_rand_like model_module.sample_probs = recording_sample_probs synchronize_torch(torch, device) started = time.perf_counter() try: with torch.inference_mode(): result = decoder.octree.sample( RecordingOccupancy(), condition, num_points=args.num_points, level=args.levels, temperature=args.temperature, algo="systematic", ) synchronize_torch(torch, device) finally: model_module.sample_probs = official_sample_probs torch.rand = original_rand torch.rand_like = original_rand_like duration_ms = (time.perf_counter() - started) * 1000 if len(neural_records) != args.levels or len(level_records) != args.levels: raise RuntimeError( f"Recorded {len(neural_records)} neural calls and {len(level_records)} samples; " f"expected {args.levels} each" ) if len(final_jitter_calls) != 1: raise RuntimeError(f"Recorded {len(final_jitter_calls)} final rand_like calls; expected one") hard_link(condition_path, output_dir / "condition.f32") condition_info = { "path": "condition.f32", "shape": list(COND_SHAPE), "dtype": "float32", "bytes": (output_dir / "condition.f32").stat().st_size, "sha256": sha256(output_dir / "condition.f32"), } levels_manifest = [] for index, (neural, sampling) in enumerate(zip(neural_records, level_records), start=1): parent_count = int(neural["x"].shape[1]) prefix = f"level_{index:02d}" files = { "parent_centers": write_array( np, output_dir / f"{prefix}_parent_centers.f32", neural["x"].float().cpu().numpy(), "