"""Tests for OrbitQuant loader support in ComfyUI-INT-Crush. Test strategy: manually construct state dicts with the OrbitQuant format (packed indices, bfloat16 norms, global RPBH/codebook tensors, format_version=4 metadata) — no converter dependency needed. """ import math import torch import pytest from _intcrush import load _oq = load("_orbitquant") _qu = load("_quant_utils") # ── Helpers ── def _make_codebook(d: int, bits: int) -> torch.Tensor: """Build a simple uniform codebook for testing. In production, this comes from Lloyd-Max on the f_d marginal. For tests, a uniform grid suffices to verify the dequant path. """ n = 2 ** bits centroids = torch.linspace(-1.0, 1.0, n, dtype=torch.float32) return centroids def _make_orbitquant_state_dict( d: int = 256, out_features: int = 32, bits: int = 4, seed: int = 42, include_adaln: bool = False, ) -> tuple[dict, dict]: """Build a synthetic OrbitQuant model's state_dict and metadata. Returns (state_dict, metadata) ready for save_file(). """ h = _oq.largest_power_of_two_dividing(d) perm, signs, h = _oq.make_rpbh_params(d, seed=seed) d_padded = perm.shape[0] codebook = _make_codebook(d, bits) codebook_key = f"_orbitquant_codebook_{d}_{bits}" # Build a fake weight: random unit directions * random norms W = torch.randn(out_features, d) norms = W.norm(dim=1, keepdim=True) W_dir = W / (norms + 1e-10) # Quantize directions to codebook # (simplified: use nearest centroid) centroids = codebook boundaries = (centroids[:-1] + centroids[1:]) / 2.0 indices = torch.searchsorted(boundaries, W_dir.reshape(-1)) indices = indices.clamp(0, len(centroids) - 1).reshape(out_features, d) # Offset to signed int8 range offset = 1 << (bits - 1) indices_int8 = (indices - offset).to(torch.int8) if bits == 4: packed = _qu.pack_int4(indices_int8).to(torch.uint8) else: packed = indices_int8 scale = norms.to(torch.bfloat16) state_dict = { "layers.0.q_proj.weight": packed, "layers.0.q_proj.weight_scale": scale, "_rpbh_perm_256": perm, "_rpbh_signs_256": signs, codebook_key: codebook, } metadata = { "int_crush.format_version": "4", "int_crush.orbitquant": "true", "int_crush.rpbh_seed": str(seed), "int_crush.codebook_bits": str(bits), "int_crush.orbitquant_dims": str(d), "int_crush.orbitquant_d_padded": f"{d}:{d_padded}", "int_crush.layers.0.q_proj.weight.quant_scheme": "orbitquant_codebook", } return state_dict, metadata # ── Tests ── class TestRPBHRotate: """Test RPBH rotation matches converter implementation.""" def test_norm_preservation(self): """‖x @ Π^T‖ = ‖x‖ (orthogonal).""" d = 256 perm, signs, h = _oq.make_rpbh_params(d, seed=42) x = torch.randn(8, d) y = _oq.rpbh_rotate(x, perm, signs, h) assert torch.allclose(x.norm(), y.norm(), rtol=1e-3) def test_cancellation(self): """(W @ Π^T) @ (x @ Π^T)^T = W @ x^T.""" for d in [256, 512, 1024]: perm, signs, h = _oq.make_rpbh_params(d, seed=42) W = torch.randn(16, d) x = torch.randn(8, d) W_rot = _oq.rpbh_rotate(W, perm, signs, h) x_rot = _oq.rpbh_rotate(x, perm, signs, h) y_rot = W_rot @ x_rot.T y_orig = W @ x.T rel_err = (y_rot - y_orig).norm() / y_orig.norm() assert rel_err < 1e-4 def test_fwht_matches_sylvester(self): """FWHT output matches Sylvester Hadamard @ x.""" h = 16 H = torch.tensor([[1.0]]) while H.shape[0] < h: H = torch.kron(torch.tensor([[1., 1.], [1., -1.]]), H) H = H / math.sqrt(h) x = torch.randn(5, h) y_fwht = _oq.fast_walsh_hadamard(x) y_matrix = x @ H.T assert torch.allclose(y_fwht, y_matrix, atol=1e-4) def test_mass_balancing(self): """Spiked input → uniform variance after RPBH (CV < 0.3).""" d = 1024 h = _oq.largest_power_of_two_dividing(d) k = d // h if k < 2: pytest.skip("single-block dimension") perm, signs, _ = _oq.make_rpbh_params(d, seed=42) n_samples = 5000 x = torch.zeros(n_samples, d) x[:, :h] = torch.randn(n_samples, h) x = x / x.norm(dim=1, keepdim=True) z = _oq.rpbh_rotate(x, perm, signs, h) var_per_coord = z.double().pow(2).mean(0) cv = var_per_coord.std().item() / var_per_coord.mean().item() assert cv < 0.3 class TestCodebookDequant: """Test codebook dequantization.""" def test_int4_roundtrip(self): """Quantize → pack → dequant ≈ original (within codebook MSE).""" d = 256 bits = 4 codebook = _make_codebook(d, bits) W = torch.randn(32, d) * 0.1 norms = W.norm(dim=1, keepdim=True) W_dir = W / (norms + 1e-10) boundaries = (codebook[:-1] + codebook[1:]) / 2.0 indices = torch.searchsorted(boundaries, W_dir.reshape(-1)) indices = indices.clamp(0, 15).reshape(32, d) offset = 1 << (bits - 1) indices_int8 = (indices - offset).to(torch.int8) packed = _qu.pack_int4(indices_int8).to(torch.uint8) W_dequant = _oq.codebook_dequant_int4( packed, norms.to(torch.bfloat16), codebook, d, d) # Should be close to original (within codebook quantization error) mse = (W - W_dequant.float()).pow(2).mean().item() assert mse < 0.01 def test_int8_roundtrip(self): """INT8 indices → codebook lookup → norms multiply.""" d = 256 bits = 8 codebook = _make_codebook(d, bits) W = torch.randn(16, d) * 0.1 norms = W.norm(dim=1, keepdim=True) W_dir = W / (norms + 1e-10) boundaries = (codebook[:-1] + codebook[1:]) / 2.0 indices = torch.searchsorted(boundaries, W_dir.reshape(-1)) indices = indices.clamp(0, 255).reshape(16, d) offset = 1 << (bits - 1) indices_int8 = (indices - offset).to(torch.int8) W_dequant = _oq.codebook_dequant_int8( indices_int8, norms.to(torch.bfloat16), codebook, d, d) mse = (W - W_dequant.float()).pow(2).mean().item() assert mse < 0.001 # INT8 should be more accurate def test_no_padding_trim(self): """d_padded > d → output is [out, d_padded] (no trim at inference).""" d = 200 # not divisible by most block sizes h = 128 # explicit block size d_padded = 256 # next multiple of 128 bits = 4 codebook = _make_codebook(d_padded, bits) norms = torch.ones(8, 1, dtype=torch.bfloat16) indices_int8 = torch.zeros(8, d_padded, dtype=torch.int8) W_dequant = _oq.codebook_dequant_int4( _qu.pack_int4(indices_int8).to(torch.uint8), norms, codebook, d, d_padded) assert W_dequant.shape == (8, d_padded) # NOT (8, d) class TestAdaLNDequant: """Test AdaLN RTN dequantization with group scales.""" def test_group_scale_shape(self): """AdaLN scales [out, d/64] → dequant produces [out, d].""" d = 256 group_size = 64 out = 32 num_groups = d // group_size scales = torch.randn(out, num_groups).abs().clamp(min=1e-4).to(torch.float16) packed = _qu.pack_int4( torch.randint(-8, 7, (out, d), dtype=torch.int8) ).to(torch.uint8) W_dequant = _oq.adaln_rtn_dequant(packed, scales, d, bits=4) assert W_dequant.shape == (out, d) def test_group_scale_correctness(self): """Each group of 64 values is multiplied by its scale.""" d = 128 group_size = 64 out = 4 num_groups = d // group_size scales = torch.tensor([[2.0, 3.0]] * out, dtype=torch.float16) # All indices = 0 → dequant value = 0 * scale = 0 # Use index 8 (offset 0) → value = -8 * scale values = torch.full((out, d), -8, dtype=torch.int8) packed = _qu.pack_int4(values).to(torch.uint8) W_dequant = _oq.adaln_rtn_dequant(packed, scales, d, bits=4) # Group 0: -8 * 2.0 = -16.0 # Group 1: -8 * 3.0 = -24.0 assert torch.allclose(W_dequant[:, :64], torch.full((out, 64), -16.0), atol=0.1) assert torch.allclose(W_dequant[:, 64:], torch.full((out, 64), -24.0), atol=0.1) class TestOrbitQuantLayoutDequantize: """Test OrbitQuantLayout.dequantize() works for both paths.""" def test_codebook_path(self): """dequantize with codebook produces correct output.""" _ql = load("quant_layout") OrbitQuantLayout = _ql.OrbitQuantLayout d = 256 bits = 4 codebook = _make_codebook(d, bits) norms = torch.ones(8, 1, dtype=torch.bfloat16) packed = _qu.pack_int4( torch.zeros(8, d, dtype=torch.int8) ).to(torch.uint8) params = OrbitQuantLayout.Params( scale=norms, orig_dtype=torch.float16, orig_shape=(8, d), quant_scheme="orbitquant_codebook", d=d, d_padded=d, bits=bits, codebook=codebook, ) W = OrbitQuantLayout.dequantize(packed, params) assert W.shape == (8, d) def test_adaln_path(self): """dequantize with adaln_rtn uses group scales.""" _ql = load("quant_layout") OrbitQuantLayout = _ql.OrbitQuantLayout d = 256 out = 8 scales = torch.ones(out, d // 64, dtype=torch.float16) packed = _qu.pack_int4( torch.zeros(out, d, dtype=torch.int8) ).to(torch.uint8) params = OrbitQuantLayout.Params( scale=scales, orig_dtype=torch.float16, orig_shape=(out, d), quant_scheme="adaln_rtn", d=d, d_padded=d, bits=4, ) W = OrbitQuantLayout.dequantize(packed, params) assert W.shape == (out, d) class TestMetadataParsing: """Test OrbitQuant metadata parsing.""" def test_parse_orbitquant_metadata(self): """Valid metadata is parsed correctly.""" metadata = { "int_crush.format_version": "4", "int_crush.orbitquant": "true", "int_crush.rpbh_seed": "42", "int_crush.codebook_bits": "4", "int_crush.orbitquant_dims": "256,512", "int_crush.orbitquant_d_padded": "256:256,512:512", } result = _oq.parse_orbitquant_metadata(metadata) assert result is not None assert result["rpbh_seed"] == 42 assert result["codebook_bits"] == 4 assert result["dims"] == [256, 512] assert result["d_padded_map"] == {256: 256, 512: 512} def test_parse_non_orbitquant(self): """Non-OrbitQuant metadata returns None.""" assert _oq.parse_orbitquant_metadata({}) is None assert _oq.parse_orbitquant_metadata(None) is None assert _oq.parse_orbitquant_metadata({ "int_crush.format_version": "3" }) is None def test_get_quant_scheme_from_metadata(self): """Per-layer quant_scheme is read correctly.""" metadata = { "int_crush.layers.0.q_proj.weight.quant_scheme": "orbitquant_codebook", "int_crush.layers.0.k_proj.weight.quant_scheme": "adaln_rtn", } assert _oq.get_quant_scheme_from_metadata(metadata, "layers.0.q_proj.") == "orbitquant_codebook" assert _oq.get_quant_scheme_from_metadata(metadata, "layers.0.k_proj.") == "adaln_rtn" assert _oq.get_quant_scheme_from_metadata(metadata, "layers.0.v_proj.") is None def test_get_quant_scheme_strips_model_prefix(self): """Metadata lookup strips model-level prefix from ComfyUI.""" metadata = { "int_crush.single_blocks.0.linear1.weight.quant_scheme": "orbitquant_codebook", "int_crush.double_blocks.0.img_attn.q_proj.weight.quant_scheme": "adaln_rtn", } # ComfyUI passes prefix with model.diffusion_model. prefix assert _oq.get_quant_scheme_from_metadata( metadata, "model.diffusion_model.single_blocks.0.linear1.") == "orbitquant_codebook" assert _oq.get_quant_scheme_from_metadata( metadata, "model.diffusion_model.double_blocks.0.img_attn.q_proj.") == "adaln_rtn" # Non-existent layer still returns None assert _oq.get_quant_scheme_from_metadata( metadata, "model.diffusion_model.single_blocks.0.linear2.") is None def test_infer_metadata_from_state_dict(self): """Metadata is inferred from global tensor keys in state_dict.""" state_dict = { "_rpbh_perm_256": torch.randperm(256), "_rpbh_signs_256": torch.ones(256), "_orbitquant_codebook_256_4": torch.linspace(-1, 1, 16), "layers.0.weight": torch.zeros(1), } result = _oq.infer_orbitquant_metadata_from_state_dict(state_dict) assert result is not None assert result["int_crush.format_version"] == "4" assert result["int_crush.orbitquant"] == "true" assert "256" in result["int_crush.orbitquant_dims"] assert result["int_crush.codebook_bits"] == "4" def test_infer_metadata_returns_none_without_globals(self): """Returns None when no OrbitQuant globals in state_dict.""" state_dict = {"layers.0.weight": torch.zeros(1)} assert _oq.infer_orbitquant_metadata_from_state_dict(state_dict) is None def test_infer_quant_scheme_from_scale(self): """Scale shape inference works correctly.""" # [out, 1] → orbitquant_codebook scale_cb = torch.ones(8, 1) assert _oq.infer_quant_scheme_from_scale(scale_cb) == "orbitquant_codebook" # [out, 4] → adaln_rtn (d=256, group_size=64 → 4 groups) scale_adaln = torch.ones(8, 4) assert _oq.infer_quant_scheme_from_scale(scale_adaln) == "adaln_rtn" class TestGlobalTensorCache: """Test OrbitQuant global tensor caching.""" def test_load_and_cache_globals(self): """Global tensors are loaded and cached correctly.""" state_dict, metadata = _make_orbitquant_state_dict(d=256, bits=4) model_path = "test_model" globals_cache = _oq.load_orbitquant_globals(state_dict, metadata, model_path) assert 256 in globals_cache["rpbh"] assert "perm" in globals_cache["rpbh"][256] assert "signs" in globals_cache["rpbh"][256] assert (256, 4) in globals_cache["codebooks"] # Verify global tensors were popped from state_dict assert "_rpbh_perm_256" not in state_dict assert "_rpbh_signs_256" not in state_dict assert "_orbitquant_codebook_256_4" not in state_dict # Verify per-layer tensors remain assert "layers.0.q_proj.weight" in state_dict # Cleanup _oq.clear_orbitquant_globals(model_path) def test_cache_idempotent(self): """Second call returns cached result without popping again.""" state_dict, metadata = _make_orbitquant_state_dict(d=256, bits=4) model_path = "test_model_idempotent" cache1 = _oq.load_orbitquant_globals(state_dict, metadata, model_path) # State dict now has globals popped — reconstruct for second call # But the function should return cached result without touching state_dict cache2 = _oq.load_orbitquant_globals(state_dict, metadata, model_path) assert cache1 is cache2 _oq.clear_orbitquant_globals(model_path) def test_clear_globals(self): """clear_orbitquant_globals removes cached data.""" state_dict, metadata = _make_orbitquant_state_dict(d=256, bits=4) model_path = "test_model_clear" _oq.load_orbitquant_globals(state_dict, metadata, model_path) assert model_path in _oq._orbitquant_globals _oq.clear_orbitquant_globals(model_path) assert model_path not in _oq._orbitquant_globals def test_clear_all_globals(self): """clear_orbitquant_globals(None) clears everything.""" sd1, meta1 = _make_orbitquant_state_dict(d=256, bits=4) sd2, meta2 = _make_orbitquant_state_dict(d=256, bits=4) _oq.load_orbitquant_globals(sd1, meta1, "model_a") _oq.load_orbitquant_globals(sd2, meta2, "model_b") _oq.clear_orbitquant_globals() assert len(_oq._orbitquant_globals) == 0 class TestLoadersDetection: """Test OrbitQuant detection helpers in _loaders.""" def test_detect_orbitquant(self): """_detect_orbitquant returns True for valid metadata.""" _ld = load("_loaders") _detect_orbitquant = _ld._detect_orbitquant assert _detect_orbitquant({ "int_crush.format_version": "4", "int_crush.orbitquant": "true", }) is True def test_detect_non_orbitquant(self): """_detect_orbitquant returns False for non-OrbitQuant metadata.""" _ld = load("_loaders") _detect_orbitquant = _ld._detect_orbitquant assert _detect_orbitquant({}) is False assert _detect_orbitquant(None) is False assert _detect_orbitquant({ "int_crush.format_version": "3", }) is False assert _detect_orbitquant({ "int_crush.format_version": "4", # missing orbitquant=true }) is False