ptwm 1.0.1__tar.gz → 1.1.0__tar.gz
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.
- {ptwm-1.0.1 → ptwm-1.1.0}/Cargo.lock +2 -2
- {ptwm-1.0.1 → ptwm-1.1.0}/Cargo.toml +1 -1
- {ptwm-1.0.1 → ptwm-1.1.0}/PKG-INFO +3 -3
- {ptwm-1.0.1 → ptwm-1.1.0}/README.md +2 -2
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/arithmetic.rs +52 -13
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/huff_llm.rs +2 -2
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/huffman.rs +6 -5
- ptwm-1.1.0/crates/ptwm-core/src/codecs/length_prefix.rs +89 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/mod.rs +1 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/order1_arithmetic.rs +5 -1
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/order1_scale_ac.rs +16 -15
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/per_group_codebook.rs +150 -9
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/rans.rs +39 -12
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/tans.rs +33 -6
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/compressor.rs +58 -17
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/container.rs +1 -1
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/discovery/mod.rs +7 -5
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/dispatch.rs +8 -9
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/context_mixing/model.rs +1 -1
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/context_mixing/squash.rs +1 -1
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/extension/id.rs +52 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/extension/mod.rs +2 -0
- ptwm-1.1.0/crates/ptwm-core/src/extension/resolve.rs +194 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/flavor/mod.rs +13 -4
- ptwm-1.1.0/crates/ptwm-core/src/flavor/native.rs +833 -0
- ptwm-1.1.0/crates/ptwm-core/src/flavor/router.rs +1532 -0
- ptwm-1.1.0/crates/ptwm-core/src/flavor/third_party.rs +225 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/flavor/wasm.rs +384 -10
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/policy/capability_check.rs +119 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transcode/base64.rs +1 -1
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transcode/manifest.rs +1 -1
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/mxfp4_deinterleave.rs +11 -2
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/op.rs +19 -12
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/predictor_xor.rs +1 -1
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/source.rs +81 -9
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/trust/org.rs +1 -1
- ptwm-1.1.0/crates/ptwm-core/tests/cuda_plane_codec_rust_only.rs +16 -0
- ptwm-1.1.0/crates/ptwm-core/tests/hardware_backend_router_native.rs +207 -0
- ptwm-1.1.0/crates/ptwm-py/src/delta_scheme.rs +78 -0
- ptwm-1.1.0/crates/ptwm-py/src/device_buffer.rs +466 -0
- ptwm-1.1.0/crates/ptwm-py/src/hardware.rs +166 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-py/src/lib.rs +7 -0
- ptwm-1.1.0/crates/ptwm-py/src/plane_codec_cuda.rs +196 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-py/src/policy.rs +15 -1
- {ptwm-1.0.1 → ptwm-1.1.0}/pyproject.toml +36 -31
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/_config.py +4 -0
- ptwm-1.1.0/python/ptwm/_rust/delta_scheme.py +13 -0
- ptwm-1.1.0/python/ptwm/_rust/hardware.py +13 -0
- ptwm-1.1.0/python/ptwm/_rust/plane_codec_cuda.py +17 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/cli/chains.py +11 -8
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/cli/compress.py +56 -1
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/cli/decompress.py +29 -4
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/cli/ext.py +16 -2
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/core/_compressor.py +24 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/core/_decompressor.py +20 -0
- ptwm-1.1.0/python/ptwm/ext_tooling/_templates/rust/_kind_delta_scheme/Cargo.toml +12 -0
- ptwm-1.1.0/python/ptwm/ext_tooling/_templates/rust/_kind_delta_scheme/manifest.toml +14 -0
- ptwm-1.1.0/python/ptwm/ext_tooling/_templates/rust/_kind_delta_scheme/src/lib.rs +128 -0
- ptwm-1.1.0/python/ptwm/ext_tooling/_templates/rust/_kind_hardware_backend/Cargo.toml +12 -0
- ptwm-1.1.0/python/ptwm/ext_tooling/_templates/rust/_kind_hardware_backend/manifest.toml +14 -0
- ptwm-1.1.0/python/ptwm/ext_tooling/_templates/rust/_kind_hardware_backend/src/lib.rs +88 -0
- {ptwm-1.0.1/python/ptwm/ext_tooling/_templates/zig → ptwm-1.1.0/python/ptwm/ext_tooling/_templates/rust}/manifest.toml +1 -1
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/build.py +42 -6
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/init.py +23 -3
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/pack.py +10 -2
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/integrations/_compress_safetensors.py +38 -18
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/preprocessing/__init__.py +4 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/preprocessing/_cache.py +61 -13
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/preprocessing/_chains.py +1 -1
- ptwm-1.0.1/crates/ptwm-core/src/flavor/native.rs +0 -313
- ptwm-1.0.1/crates/ptwm-core/src/flavor/router.rs +0 -576
- ptwm-1.0.1/crates/ptwm-core/src/flavor/third_party.rs +0 -92
- {ptwm-1.0.1 → ptwm-1.1.0}/LICENSE +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/Cargo.toml +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/build.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/data/bundled-keys.toml +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/data/vendor_table.toml +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/chain/dispatch.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/chain/graph.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/chain/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/chain/runtime.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/chain/validate.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/chain/wire.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codec.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codec_tagged.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/context_mixing.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/fpc.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/identity.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/neural_predictor.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/zstd.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/codecs/zstd_dict.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/delta.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/dtype.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/arithmetic/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/arithmetic/model.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/context_mixing/coder.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/context_mixing/mixer.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/context_mixing/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/huff_llm/group_codec.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/huff_llm/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/huffman/bitstream.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/huffman/compress.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/huffman/decompress.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/huffman/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/huffman/tree.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/huffman/weights.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/neural_predictor/coder.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/neural_predictor/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/neural_predictor/net.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/outcome.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/rans/compress.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/rans/decompress.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/rans/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/stream_frame.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/entropy/tans/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/error.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/extension/builder.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/extension/builtins.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/extension/capability.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/extension/dispatch.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/extension/error.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/extension/kind.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/extension/lifecycle.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/extension/manifest.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/extension/table.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/fit/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/fit/order1.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/fit/per_group_codebook.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/flavor/abi.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/flavor/host.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/header.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/index.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/install/git.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/install/https.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/install/local.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/install/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/install/oci.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/install/pip.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/layout.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/lib.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/metadata.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/plane_record.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/policy/file.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/policy/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/policy/native_deps.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/policy/resolve.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/prelude.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/quantize.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/range_coder.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/select.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/split/dtype16.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/split/dtype32.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/split/dtype64.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/split/dtype8.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/split/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/tensor_record.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transcode/jcs.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transcode/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transcode/tests.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/alpha_stable_normalize.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/bit_reorder_fp8.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/bit_reorder_ieee.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/block_microscaling_repack.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/burrows_wheeler.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/byte_passthrough.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/byte_split.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/concat.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/delta.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/entropy.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/fusion.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/index_pack.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/int_delta.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/mantissa_zero.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/move_to_front.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/nibble_split.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/reshape.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/spherical_normalize.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/transforms/terminal.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/trust/bundled.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/trust/keyring.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/trust/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/trust/signature.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/trust/verifier.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/types/descriptor.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/types/mod.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/types/plane_role.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-core/src/types/role.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-py/Cargo.toml +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-py/src/ext.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-py/src/host_flavor.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-py/src/inspect.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/crates/ptwm-py/src/trust.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/_exceptions.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/_loader.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/_rust/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/_rust/_errors.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/_rust/ext.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/_rust/host.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/_rust/policy.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/_rust/trust.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ablation/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ablation/_attribute.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ablation/_bench.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ablation/_compare.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ablation/_replay.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ablation/_resolve.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/classify/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/classify/_audit.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/classify/_chain.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/classify/_flags.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/classify/_heuristic.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/classify/_hf_quant.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/classify/_protocol.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/classify/_ptwm_config.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/classify/_role.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/cli/README.md +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/cli/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/cli/bench.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/cli/main.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/cli/policy.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/cli/trust.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/cli/utils.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/codecs/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/core/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/delta/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/entropy/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/_templates/assemblyscript/manifest.toml +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/_templates/assemblyscript/package.json +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/_templates/assemblyscript/src/index.ts +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/_templates/c/Makefile +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/_templates/c/manifest.toml +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/_templates/c/src/lib.c +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/_templates/rust/Cargo.toml +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/_templates/rust/src/lib.rs +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/_templates/zig/build.zig +0 -0
- {ptwm-1.0.1/python/ptwm/ext_tooling/_templates/rust → ptwm-1.1.0/python/ptwm/ext_tooling/_templates/zig}/manifest.toml +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/_templates/zig/src/main.zig +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/ext_tooling/sign.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/integrations/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/integrations/_hf.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/integrations/_safetensors.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/preprocessing/_explorer.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/preprocessing/_plane.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/random_access/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/sharding/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/sharding/_index.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/sharding/_reader.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/sharding/_sharder.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/sharding/_writer.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/stores/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/stores/_common.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/stores/_lmdb.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/stores/_webdataset.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/utils/__init__.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/utils/_decode.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/utils/_patch.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/utils/_safetensors.py +0 -0
- {ptwm-1.0.1 → ptwm-1.1.0}/python/ptwm/utils/_torch.py +0 -0
|
@@ -1945,7 +1945,7 @@ dependencies = [
|
|
|
1945
1945
|
|
|
1946
1946
|
[[package]]
|
|
1947
1947
|
name = "ptwm-core"
|
|
1948
|
-
version = "1.0
|
|
1948
|
+
version = "1.1.0"
|
|
1949
1949
|
dependencies = [
|
|
1950
1950
|
"blake3",
|
|
1951
1951
|
"ciborium",
|
|
@@ -1980,7 +1980,7 @@ dependencies = [
|
|
|
1980
1980
|
|
|
1981
1981
|
[[package]]
|
|
1982
1982
|
name = "ptwm-py"
|
|
1983
|
-
version = "1.0
|
|
1983
|
+
version = "1.1.0"
|
|
1984
1984
|
dependencies = [
|
|
1985
1985
|
"hex",
|
|
1986
1986
|
"memmap2",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ptwm
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Classifier: Development Status :: 5 - Production/Stable
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -354,8 +354,8 @@ fields; see its docstring for the full list.
|
|
|
354
354
|
| `bfloat16` / `float16` | Bit reorder + 2-plane byte split | Exponent → plane 1 |
|
|
355
355
|
| `float8_e4m3fn` / `float8_e5m2` | Bit reorder + 2-plane nibble split | Exponent → high nibble |
|
|
356
356
|
| `float4_e2m1fn_x2` (weight nibbles) | Passthrough, per-plane trial-encode | `PerGroupCodebook` competes against Huffman / rANS on the nibble-packed byte stream |
|
|
357
|
-
| MXFP4 scale (`uint8`, E8M0) |
|
|
358
|
-
| NVFP4 scale (FP8-E4M3) | `Order1ScaleAC` (per-row lag-1 arithmetic coding) | Mantissa bits give exploitable row autocorrelation
|
|
357
|
+
| MXFP4 scale (`uint8`, E8M0) | `Order1ScaleAC` (per-row lag-1 arithmetic coding), per-plane trial-encode | Rows are autocorrelated: on gpt-oss-20b the entropy given the previous scale in the row is 1.20 bits, against 1.89 bits unconditioned |
|
|
358
|
+
| NVFP4 scale (FP8-E4M3) | `Order1ScaleAC` (per-row lag-1 arithmetic coding) | Mantissa bits give exploitable row autocorrelation |
|
|
359
359
|
| `int8`, `uint8`, `int16`, `int32`, `int64`, `bool` | Single stream | No byte split or bit reorder yet; whatever wins per-plane trial-encode on the raw bytes |
|
|
360
360
|
|
|
361
361
|
MXFP4 / NVFP4 tensors are compressed as a pair: the packed FP4 weight
|
|
@@ -314,8 +314,8 @@ fields; see its docstring for the full list.
|
|
|
314
314
|
| `bfloat16` / `float16` | Bit reorder + 2-plane byte split | Exponent → plane 1 |
|
|
315
315
|
| `float8_e4m3fn` / `float8_e5m2` | Bit reorder + 2-plane nibble split | Exponent → high nibble |
|
|
316
316
|
| `float4_e2m1fn_x2` (weight nibbles) | Passthrough, per-plane trial-encode | `PerGroupCodebook` competes against Huffman / rANS on the nibble-packed byte stream |
|
|
317
|
-
| MXFP4 scale (`uint8`, E8M0) |
|
|
318
|
-
| NVFP4 scale (FP8-E4M3) | `Order1ScaleAC` (per-row lag-1 arithmetic coding) | Mantissa bits give exploitable row autocorrelation
|
|
317
|
+
| MXFP4 scale (`uint8`, E8M0) | `Order1ScaleAC` (per-row lag-1 arithmetic coding), per-plane trial-encode | Rows are autocorrelated: on gpt-oss-20b the entropy given the previous scale in the row is 1.20 bits, against 1.89 bits unconditioned |
|
|
318
|
+
| NVFP4 scale (FP8-E4M3) | `Order1ScaleAC` (per-row lag-1 arithmetic coding) | Mantissa bits give exploitable row autocorrelation |
|
|
319
319
|
| `int8`, `uint8`, `int16`, `int32`, `int64`, `bool` | Single stream | No byte split or bit reorder yet; whatever wins per-plane trial-encode on the raw bytes |
|
|
320
320
|
|
|
321
321
|
MXFP4 / NVFP4 tensors are compressed as a pair: the packed FP4 weight
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
//! planes).
|
|
6
6
|
|
|
7
7
|
use crate::codec::{CodecId, Encoded, PlaneCodec};
|
|
8
|
+
use crate::codecs::length_prefix;
|
|
8
9
|
use crate::entropy::arithmetic::{
|
|
9
10
|
Order0Adaptive, Order0Static, Order1Adaptive, decode_bytes, encode_bytes,
|
|
10
11
|
};
|
|
@@ -12,22 +13,35 @@ use crate::error::PtwmCoreError;
|
|
|
12
13
|
use crate::layout::PlaneLayout;
|
|
13
14
|
use crate::types::descriptor::PlaneDescriptor;
|
|
14
15
|
|
|
15
|
-
/// Absolute cap on the framed decoded length, mirroring `rans.rs`. Guards a
|
|
16
|
-
/// hostile length prefix from driving a multi-GiB decode loop.
|
|
17
|
-
const MAX_DECODED_LEN: usize = 1 << 30; // 1 GiB
|
|
18
|
-
|
|
19
16
|
/// Prepend the true decoded length (u32 LE) so decode is self-delimiting.
|
|
20
17
|
///
|
|
18
|
+
/// Fails when the decoder would refuse the length (see
|
|
19
|
+
/// [`length_prefix::accepted`]); these coders have no raw fallback.
|
|
20
|
+
///
|
|
21
21
|
/// The container's `decode` receives a `decoded_len` derived from the
|
|
22
22
|
/// *source-tensor* descriptor, which for byte-split planes is larger than the
|
|
23
23
|
/// actual plane length. Self-delimiting codecs (Huffman, rANS, …) ignore that
|
|
24
24
|
/// argument and recover the length from their own payload; the arithmetic
|
|
25
25
|
/// coders do the same here rather than trusting `decoded_len`.
|
|
26
|
-
pub(crate) fn frame_payload(
|
|
26
|
+
pub(crate) fn frame_payload(
|
|
27
|
+
decoded_len: usize,
|
|
28
|
+
payload: &[u8],
|
|
29
|
+
codec: &'static str,
|
|
30
|
+
) -> Result<Vec<u8>, PtwmCoreError> {
|
|
31
|
+
if !length_prefix::accepted(decoded_len, payload.len()) {
|
|
32
|
+
return Err(PtwmCoreError::CodecEncode {
|
|
33
|
+
codec,
|
|
34
|
+
msg: format!(
|
|
35
|
+
"decoded length {decoded_len} with {} encoded bytes exceeds the length-prefix limit",
|
|
36
|
+
payload.len()
|
|
37
|
+
),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
27
40
|
let mut out = Vec::with_capacity(4 + payload.len());
|
|
41
|
+
// `accepted` guarantees the length fits the u32 prefix.
|
|
28
42
|
out.extend_from_slice(&(decoded_len as u32).to_le_bytes());
|
|
29
43
|
out.extend_from_slice(payload);
|
|
30
|
-
out
|
|
44
|
+
Ok(out)
|
|
31
45
|
}
|
|
32
46
|
|
|
33
47
|
/// Inverse of [`frame_payload`]: read the length prefix and return the rest.
|
|
@@ -42,13 +56,15 @@ pub(crate) fn unframe_payload<'a>(
|
|
|
42
56
|
});
|
|
43
57
|
}
|
|
44
58
|
let n = u32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]]) as usize;
|
|
45
|
-
|
|
59
|
+
let body = &payload[4..];
|
|
60
|
+
// Guards a hostile length prefix from driving a multi-GiB decode loop.
|
|
61
|
+
if !length_prefix::accepted(n, body.len()) {
|
|
46
62
|
return Err(PtwmCoreError::CodecDecode {
|
|
47
63
|
codec,
|
|
48
64
|
msg: format!("implausible decoded length {n}"),
|
|
49
65
|
});
|
|
50
66
|
}
|
|
51
|
-
Ok((n,
|
|
67
|
+
Ok((n, body))
|
|
52
68
|
}
|
|
53
69
|
|
|
54
70
|
/// Order-0 arithmetic coder with a serialized normalized table.
|
|
@@ -85,7 +101,11 @@ impl PlaneCodec for ArithmeticO0 {
|
|
|
85
101
|
});
|
|
86
102
|
}
|
|
87
103
|
let mut model = Order0Static::fit(plane);
|
|
88
|
-
let payload = frame_payload(
|
|
104
|
+
let payload = frame_payload(
|
|
105
|
+
plane.len(),
|
|
106
|
+
&encode_bytes(&mut model, plane),
|
|
107
|
+
"arithmetic_o0",
|
|
108
|
+
)?;
|
|
89
109
|
Ok(Encoded {
|
|
90
110
|
state_bytes: model.serialize(),
|
|
91
111
|
state_format_version: 1,
|
|
@@ -156,7 +176,8 @@ impl PlaneCodec for ArithmeticO0Adaptive {
|
|
|
156
176
|
let payload = frame_payload(
|
|
157
177
|
plane.len(),
|
|
158
178
|
&encode_bytes(&mut Order0Adaptive::new(), plane),
|
|
159
|
-
|
|
179
|
+
"arithmetic_o0_adaptive",
|
|
180
|
+
)?;
|
|
160
181
|
Ok(Encoded {
|
|
161
182
|
state_bytes: Vec::new(),
|
|
162
183
|
state_format_version: 0,
|
|
@@ -229,7 +250,8 @@ impl PlaneCodec for ArithmeticO1 {
|
|
|
229
250
|
let payload = frame_payload(
|
|
230
251
|
plane.len(),
|
|
231
252
|
&encode_bytes(&mut Order1Adaptive::new(), plane),
|
|
232
|
-
|
|
253
|
+
"arithmetic_o1",
|
|
254
|
+
)?;
|
|
233
255
|
Ok(Encoded {
|
|
234
256
|
state_bytes: Vec::new(),
|
|
235
257
|
state_format_version: 0,
|
|
@@ -419,8 +441,8 @@ mod tests {
|
|
|
419
441
|
let data: Vec<u8> = (0..262144)
|
|
420
442
|
.map(|i| match i % 16 {
|
|
421
443
|
0..=9 => 0x40u8,
|
|
422
|
-
10
|
|
423
|
-
13
|
|
444
|
+
10..=12 => 0x41,
|
|
445
|
+
13..=14 => 0x3F,
|
|
424
446
|
_ => 0x42,
|
|
425
447
|
})
|
|
426
448
|
.collect();
|
|
@@ -435,4 +457,21 @@ mod tests {
|
|
|
435
457
|
"arithmetic O0 ({ac_total}) must not exceed Huffman ({huff_total}) on a structured plane",
|
|
436
458
|
);
|
|
437
459
|
}
|
|
460
|
+
|
|
461
|
+
#[test]
|
|
462
|
+
fn unframe_rejects_a_short_payload_declaring_a_large_plane() {
|
|
463
|
+
let mut payload = length_prefix::SHORT_BODY_DECLARED_LEN
|
|
464
|
+
.to_le_bytes()
|
|
465
|
+
.to_vec();
|
|
466
|
+
payload.extend_from_slice(&[0u8; 64]);
|
|
467
|
+
assert!(unframe_payload(&payload, "arithmetic_o0").is_err());
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
#[test]
|
|
471
|
+
fn frame_and_unframe_agree_on_the_length() {
|
|
472
|
+
let framed = frame_payload(5, &[1, 2, 3], "arithmetic_o0").unwrap();
|
|
473
|
+
let (n, body) = unframe_payload(&framed, "arithmetic_o0").unwrap();
|
|
474
|
+
assert_eq!((n, body), (5, &[1u8, 2, 3][..]));
|
|
475
|
+
assert!(frame_payload(length_prefix::RATIO_FREE_LEN + 1, &[0], "arithmetic_o0").is_err());
|
|
476
|
+
}
|
|
438
477
|
}
|
|
@@ -64,7 +64,7 @@ impl PlaneCodec for HuffLlm5Bit {
|
|
|
64
64
|
_layout: &PlaneLayout,
|
|
65
65
|
) -> bool {
|
|
66
66
|
// Skip tiny planes (three table headers don't amortize) and odd lengths.
|
|
67
|
-
plane.len() >= MIN_WORDS * 2 && plane.len()
|
|
67
|
+
plane.len() >= MIN_WORDS * 2 && plane.len().is_multiple_of(2)
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
fn encode(
|
|
@@ -82,7 +82,7 @@ impl PlaneCodec for HuffLlm5Bit {
|
|
|
82
82
|
// Empty or odd-length → raw store (still total). Short-circuit empty
|
|
83
83
|
// before allocating `words`, since trial-encode hits this path on every
|
|
84
84
|
// candidate.
|
|
85
|
-
if plane.is_empty() || plane.len()
|
|
85
|
+
if plane.is_empty() || !plane.len().is_multiple_of(2) {
|
|
86
86
|
return Ok(raw_store(plane));
|
|
87
87
|
}
|
|
88
88
|
let words: Vec<u16> = plane
|
|
@@ -57,10 +57,10 @@ impl PlaneCodec for Huffman {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
let mut buf = vec![0u8; huffman_output_bound(plane.len())];
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
let outcome = huffman::compress_outcome(&mut buf, plane)?;
|
|
61
|
+
match (outcome, u32::try_from(plane.len())) {
|
|
62
|
+
(CompressOutcome::Encoded(n), Ok(orig_len)) => {
|
|
62
63
|
// TAG_HUF | orig_len (4 bytes LE) | huffman-encoded bytes
|
|
63
|
-
let orig_len = plane.len() as u32;
|
|
64
64
|
let mut payload = Vec::with_capacity(1 + 4 + n);
|
|
65
65
|
payload.push(TAG_HUF);
|
|
66
66
|
payload.extend_from_slice(&orig_len.to_le_bytes());
|
|
@@ -71,9 +71,10 @@ impl PlaneCodec for Huffman {
|
|
|
71
71
|
payload,
|
|
72
72
|
})
|
|
73
73
|
}
|
|
74
|
-
|
|
74
|
+
_ => {
|
|
75
75
|
// NotBeneficial / Incompressible / DstTooSmall /
|
|
76
|
-
// LenOverflow
|
|
76
|
+
// LenOverflow, or a plane longer than the u32 length
|
|
77
|
+
// prefix → store raw
|
|
77
78
|
let mut payload = Vec::with_capacity(1 + plane.len());
|
|
78
79
|
payload.push(TAG_RAW);
|
|
79
80
|
payload.extend_from_slice(plane);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
//! Acceptance rule for the decoded length a plane payload declares.
|
|
2
|
+
//!
|
|
3
|
+
//! rANS, tANS, and the arithmetic coders prefix their payload with the
|
|
4
|
+
//! decoded length as a little-endian `u32`, and the decoder sizes its output
|
|
5
|
+
//! (or its decode loop) from that prefix before reading the body. A corrupted
|
|
6
|
+
//! or hostile prefix must not drive an arbitrarily large allocation, so the
|
|
7
|
+
//! decoder checks it against [`accepted`]. Encoders apply the same rule before
|
|
8
|
+
//! writing a prefix, so every plane they emit is one their decoder accepts.
|
|
9
|
+
|
|
10
|
+
/// Decoded length accepted at any compression ratio.
|
|
11
|
+
///
|
|
12
|
+
/// These coders reach very high ratios on near-degenerate distributions (an
|
|
13
|
+
/// all-zero 64 KiB plane encodes to about 30 bytes), so below this size the
|
|
14
|
+
/// rule bounds the length alone.
|
|
15
|
+
pub(crate) const RATIO_FREE_LEN: usize = 1 << 30; // 1 GiB
|
|
16
|
+
|
|
17
|
+
/// Largest decoded-to-encoded length ratio accepted above [`RATIO_FREE_LEN`].
|
|
18
|
+
///
|
|
19
|
+
/// A payload that declares more than [`RATIO_FREE_LEN`] bytes must carry at
|
|
20
|
+
/// least `1 / MAX_RATIO` of that length as encoded body, which bounds the
|
|
21
|
+
/// allocation a short payload can request. Weight planes this large (a BF16
|
|
22
|
+
/// embedding or output projection of a large-vocabulary model) compress far
|
|
23
|
+
/// less than this.
|
|
24
|
+
pub(crate) const MAX_RATIO: usize = 64;
|
|
25
|
+
|
|
26
|
+
/// Whether a payload declaring `decoded_len` bytes from an encoded body of
|
|
27
|
+
/// `body_len` bytes is accepted.
|
|
28
|
+
///
|
|
29
|
+
/// Lengths that do not fit the `u32` prefix are never accepted.
|
|
30
|
+
pub(crate) fn accepted(decoded_len: usize, body_len: usize) -> bool {
|
|
31
|
+
u32::try_from(decoded_len).is_ok()
|
|
32
|
+
&& (decoded_len <= RATIO_FREE_LEN || decoded_len <= body_len.saturating_mul(MAX_RATIO))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Bytes from a skewed distribution (about 2 bits per byte), long enough to
|
|
36
|
+
/// exercise lengths above [`RATIO_FREE_LEN`] while staying far below
|
|
37
|
+
/// [`MAX_RATIO`].
|
|
38
|
+
#[cfg(test)]
|
|
39
|
+
pub(crate) fn skewed_bytes(len: usize) -> Vec<u8> {
|
|
40
|
+
let mut x: u64 = 0x9E37_79B9_7F4A_7C15;
|
|
41
|
+
(0..len)
|
|
42
|
+
.map(|_| {
|
|
43
|
+
x ^= x << 13;
|
|
44
|
+
x ^= x >> 7;
|
|
45
|
+
x ^= x << 17;
|
|
46
|
+
x.trailing_zeros().min(15) as u8
|
|
47
|
+
})
|
|
48
|
+
.collect()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// A payload body shorter than `1 / MAX_RATIO` of the 3 GiB it declares.
|
|
52
|
+
#[cfg(test)]
|
|
53
|
+
pub(crate) const SHORT_BODY_DECLARED_LEN: u32 = 3 << 30;
|
|
54
|
+
|
|
55
|
+
#[cfg(test)]
|
|
56
|
+
mod tests {
|
|
57
|
+
use super::*;
|
|
58
|
+
|
|
59
|
+
#[test]
|
|
60
|
+
fn any_ratio_is_accepted_up_to_the_ratio_free_length() {
|
|
61
|
+
assert!(accepted(0, 0));
|
|
62
|
+
assert!(accepted(RATIO_FREE_LEN, 1));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#[test]
|
|
66
|
+
fn a_large_plane_at_a_weight_like_ratio_is_accepted() {
|
|
67
|
+
// A BF16 embedding of a 128256-token, 8192-wide model, at the ratio
|
|
68
|
+
// rANS reached on it.
|
|
69
|
+
let decoded = 128_256 * 8192 * 2;
|
|
70
|
+
assert!(decoded > RATIO_FREE_LEN);
|
|
71
|
+
assert!(accepted(decoded, 1_611_325_931));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#[test]
|
|
75
|
+
fn a_short_body_cannot_declare_a_large_plane() {
|
|
76
|
+
let decoded = RATIO_FREE_LEN + 1;
|
|
77
|
+
assert!(!accepted(decoded, 16));
|
|
78
|
+
assert!(!accepted(decoded, decoded / MAX_RATIO - 1));
|
|
79
|
+
assert!(accepted(decoded, decoded.div_ceil(MAX_RATIO)));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
#[test]
|
|
83
|
+
#[cfg(target_pointer_width = "64")]
|
|
84
|
+
fn lengths_beyond_the_u32_prefix_are_rejected() {
|
|
85
|
+
let too_long = u32::MAX as usize + 1;
|
|
86
|
+
assert!(!accepted(too_long, too_long));
|
|
87
|
+
assert!(accepted(u32::MAX as usize, u32::MAX as usize));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -72,7 +72,11 @@ impl PlaneCodec for Order1Arithmetic {
|
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
let mut model = Order1Static::fit(plane);
|
|
75
|
-
let payload = frame_payload(
|
|
75
|
+
let payload = frame_payload(
|
|
76
|
+
plane.len(),
|
|
77
|
+
&encode_bytes(&mut model, plane),
|
|
78
|
+
"order1_arithmetic",
|
|
79
|
+
)?;
|
|
76
80
|
Ok(Encoded {
|
|
77
81
|
state_bytes: model.serialize(),
|
|
78
82
|
state_format_version: STATE_FORMAT_VERSION,
|
|
@@ -453,16 +453,19 @@ impl PlaneCodec for Order1ScaleAC {
|
|
|
453
453
|
|
|
454
454
|
fn accepts(&self, descriptor: &PlaneDescriptor) -> bool {
|
|
455
455
|
// O1SAC requires byte-width Scale or GlobalScale planes with row layout
|
|
456
|
-
//
|
|
457
|
-
//
|
|
458
|
-
//
|
|
459
|
-
//
|
|
460
|
-
//
|
|
461
|
-
//
|
|
462
|
-
//
|
|
456
|
+
// and a vetted scale format. The codec models per-row lag-1 PMFs over
|
|
457
|
+
// scale bytes. FP8 scales (E4M3, E5M2) carry that structure, and so do
|
|
458
|
+
// MXFP4's E8M0 block scales: across gpt-oss-20b's 597M E8M0 scales the
|
|
459
|
+
// entropy conditioned on the previous scale in the row is 1.20
|
|
460
|
+
// bits against 1.89 bits unconditioned. Trial encoding still picks the
|
|
461
|
+
// smallest codec per plane. Future scale formats need the same vetting
|
|
462
|
+
// before being admitted.
|
|
463
463
|
let role_ok = match descriptor.role {
|
|
464
464
|
Role::Scale { format } | Role::GlobalScale { format } => {
|
|
465
|
-
matches!(
|
|
465
|
+
matches!(
|
|
466
|
+
format,
|
|
467
|
+
ScaleFormat::E4M3 | ScaleFormat::E5M2 | ScaleFormat::E8M0
|
|
468
|
+
)
|
|
466
469
|
}
|
|
467
470
|
_ => false,
|
|
468
471
|
};
|
|
@@ -1081,10 +1084,8 @@ mod capability_tests {
|
|
|
1081
1084
|
}
|
|
1082
1085
|
|
|
1083
1086
|
#[test]
|
|
1084
|
-
fn
|
|
1085
|
-
// E8M0 (MXFP4 block scale)
|
|
1086
|
-
// different from FP8 scales (E4M3 / E5M2) and outside O1SAC's design
|
|
1087
|
-
// domain.
|
|
1087
|
+
fn o1sac_accepts_e8m0_scale() {
|
|
1088
|
+
// E8M0 (MXFP4 block scale) rows are autocorrelated like FP8 scale rows.
|
|
1088
1089
|
let c = Order1ScaleAC;
|
|
1089
1090
|
let d = descriptor(
|
|
1090
1091
|
Role::Scale {
|
|
@@ -1094,11 +1095,11 @@ mod capability_tests {
|
|
|
1094
1095
|
Layout::Rows { row_len: 32 },
|
|
1095
1096
|
false,
|
|
1096
1097
|
);
|
|
1097
|
-
assert!(
|
|
1098
|
+
assert!(c.accepts(&d));
|
|
1098
1099
|
}
|
|
1099
1100
|
|
|
1100
1101
|
#[test]
|
|
1101
|
-
fn
|
|
1102
|
+
fn o1sac_accepts_e8m0_global_scale() {
|
|
1102
1103
|
let c = Order1ScaleAC;
|
|
1103
1104
|
let d = descriptor(
|
|
1104
1105
|
Role::GlobalScale {
|
|
@@ -1108,7 +1109,7 @@ mod capability_tests {
|
|
|
1108
1109
|
Layout::Rows { row_len: 16 },
|
|
1109
1110
|
false,
|
|
1110
1111
|
);
|
|
1111
|
-
assert!(
|
|
1112
|
+
assert!(c.accepts(&d));
|
|
1112
1113
|
}
|
|
1113
1114
|
|
|
1114
1115
|
#[test]
|
|
@@ -405,10 +405,28 @@ impl PlaneCodec for PerGroupCodebook {
|
|
|
405
405
|
CodecId::PerGroupCodebook
|
|
406
406
|
}
|
|
407
407
|
|
|
408
|
+
/// Accept expanded FP4 value planes whose length divides into whole
|
|
409
|
+
/// groups.
|
|
410
|
+
///
|
|
411
|
+
/// The codec models one nibble per byte, and `GROUP_SIZE` of 32 is one
|
|
412
|
+
/// MXFP4 block: the unit that shares a scale, and therefore the unit
|
|
413
|
+
/// worth giving its own codebook. `MxFp4Deinterleave` produces exactly
|
|
414
|
+
/// that, 32 single-nibble slots per block.
|
|
415
|
+
///
|
|
416
|
+
/// Two exclusions are deliberate. A *packed* plane, two values per
|
|
417
|
+
/// byte, is declined rather than misread: reading one would take low
|
|
418
|
+
/// nibbles only and return them with the high half zeroed, silently
|
|
419
|
+
/// losing half the data. Such a plane must be deinterleaved first. And
|
|
420
|
+
/// a length that is not a whole number of groups is declined here
|
|
421
|
+
/// rather than failing inside `encode`, because dispatch drops the
|
|
422
|
+
/// whole candidate chain when a codec errors and packed FP4 has only
|
|
423
|
+
/// one chain to drop. Declining keeps an `encode` error meaning what it
|
|
424
|
+
/// should: an invariant was violated, not merely an unsuitable input.
|
|
408
425
|
fn accepts(&self, descriptor: &PlaneDescriptor) -> bool {
|
|
409
|
-
descriptor.is_nibble_packed
|
|
426
|
+
!descriptor.is_nibble_packed
|
|
410
427
|
&& matches!(descriptor.role, Role::Value { .. })
|
|
411
428
|
&& descriptor.element_width == ElementWidth::Nibble
|
|
429
|
+
&& (descriptor.length_bytes as usize).is_multiple_of(GROUP_SIZE)
|
|
412
430
|
}
|
|
413
431
|
|
|
414
432
|
fn priority_for(&self, descriptor: &PlaneDescriptor) -> i8 {
|
|
@@ -793,27 +811,27 @@ mod capability_tests {
|
|
|
793
811
|
}
|
|
794
812
|
|
|
795
813
|
#[test]
|
|
796
|
-
fn
|
|
814
|
+
fn pgc_accepts_expanded_value_nibble() {
|
|
797
815
|
let c = PerGroupCodebook;
|
|
798
816
|
let d = descriptor(
|
|
799
817
|
Role::Value {
|
|
800
818
|
format: ValueFormat::Fp4E2m1,
|
|
801
819
|
},
|
|
802
820
|
ElementWidth::Nibble,
|
|
803
|
-
|
|
821
|
+
false,
|
|
804
822
|
);
|
|
805
823
|
assert!(c.accepts(&d));
|
|
806
824
|
}
|
|
807
825
|
|
|
808
826
|
#[test]
|
|
809
|
-
fn
|
|
827
|
+
fn pgc_rejects_packed_plane() {
|
|
810
828
|
let c = PerGroupCodebook;
|
|
811
829
|
let d = descriptor(
|
|
812
830
|
Role::Value {
|
|
813
831
|
format: ValueFormat::Fp4E2m1,
|
|
814
832
|
},
|
|
815
833
|
ElementWidth::Nibble,
|
|
816
|
-
|
|
834
|
+
true,
|
|
817
835
|
);
|
|
818
836
|
assert!(!c.accepts(&d));
|
|
819
837
|
}
|
|
@@ -826,7 +844,7 @@ mod capability_tests {
|
|
|
826
844
|
format: ScaleFormat::E4M3,
|
|
827
845
|
},
|
|
828
846
|
ElementWidth::Nibble,
|
|
829
|
-
|
|
847
|
+
false,
|
|
830
848
|
);
|
|
831
849
|
assert!(!c.accepts(&d));
|
|
832
850
|
}
|
|
@@ -839,7 +857,7 @@ mod capability_tests {
|
|
|
839
857
|
format: ValueFormat::Fp4E2m1,
|
|
840
858
|
},
|
|
841
859
|
ElementWidth::Byte,
|
|
842
|
-
|
|
860
|
+
false,
|
|
843
861
|
);
|
|
844
862
|
assert!(!c.accepts(&d));
|
|
845
863
|
}
|
|
@@ -852,7 +870,7 @@ mod capability_tests {
|
|
|
852
870
|
format: ValueFormat::Fp4E2m1,
|
|
853
871
|
},
|
|
854
872
|
ElementWidth::Nibble,
|
|
855
|
-
|
|
873
|
+
false,
|
|
856
874
|
);
|
|
857
875
|
assert_eq!(c.priority_for(&d), 10);
|
|
858
876
|
}
|
|
@@ -865,8 +883,131 @@ mod capability_tests {
|
|
|
865
883
|
format: ScaleFormat::E4M3,
|
|
866
884
|
},
|
|
867
885
|
ElementWidth::Nibble,
|
|
868
|
-
|
|
886
|
+
false,
|
|
869
887
|
);
|
|
870
888
|
assert_eq!(c.priority_for(&d), i8::MIN);
|
|
871
889
|
}
|
|
872
890
|
}
|
|
891
|
+
|
|
892
|
+
/// End-to-end coverage for the producer this codec is actually built for.
|
|
893
|
+
///
|
|
894
|
+
/// The suite previously exercised the codec only on hand-built planes. It
|
|
895
|
+
/// never drove the op that supplies it in practice, which is how a
|
|
896
|
+
/// descriptor mismatch between the two survived: `MxFp4Deinterleave`
|
|
897
|
+
/// labelled its output nibble-packed while emitting one nibble per byte,
|
|
898
|
+
/// and the codec's own contract expects the expanded form.
|
|
899
|
+
#[cfg(test)]
|
|
900
|
+
mod deinterleave_integration_tests {
|
|
901
|
+
use super::*;
|
|
902
|
+
use crate::transforms::mxfp4_deinterleave::MxFp4Deinterleave;
|
|
903
|
+
use crate::transforms::op::{Op, Plane};
|
|
904
|
+
use crate::types::descriptor::{Layout, PlaneDescriptor};
|
|
905
|
+
use crate::types::role::Role;
|
|
906
|
+
|
|
907
|
+
const BLOCK_BYTES: usize = 17;
|
|
908
|
+
|
|
909
|
+
/// OCP MXFP4 wire bytes: 16 packed-nibble bytes then one E8M0 scale.
|
|
910
|
+
fn mxfp4_blocks(n_blocks: usize, seed: u64) -> Vec<u8> {
|
|
911
|
+
let mut s = seed.wrapping_mul(0x9E37_79B9_7F4A_7C15) | 1;
|
|
912
|
+
let mut out = Vec::with_capacity(n_blocks * BLOCK_BYTES);
|
|
913
|
+
for b in 0..n_blocks {
|
|
914
|
+
for _ in 0..16 {
|
|
915
|
+
s ^= s << 13;
|
|
916
|
+
s ^= s >> 7;
|
|
917
|
+
s ^= s << 17;
|
|
918
|
+
// Skewed within a block, varying across blocks, so a
|
|
919
|
+
// per-block codebook has structure to find.
|
|
920
|
+
let lo = (s % 4 + (b as u64 % 3) * 4) as u8 & 0x0F;
|
|
921
|
+
let hi = ((s >> 8) % 4 + (b as u64 % 3) * 4) as u8 & 0x0F;
|
|
922
|
+
out.push(lo | (hi << 4));
|
|
923
|
+
}
|
|
924
|
+
out.push(0x80 | (b as u8 & 0x0F));
|
|
925
|
+
}
|
|
926
|
+
out
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
fn raw_descriptor(len: usize) -> PlaneDescriptor {
|
|
930
|
+
PlaneDescriptor {
|
|
931
|
+
role: Role::Raw,
|
|
932
|
+
element_width: ElementWidth::Byte,
|
|
933
|
+
length_bytes: len as u64,
|
|
934
|
+
layout: Layout::Flat,
|
|
935
|
+
derives_from_tensor: None,
|
|
936
|
+
residual_of: None,
|
|
937
|
+
is_nibble_packed: false,
|
|
938
|
+
vendor_bytes: vec![],
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
#[test]
|
|
943
|
+
fn codec_accepts_and_round_trips_the_deinterleaved_value_plane() {
|
|
944
|
+
let n_blocks = 8;
|
|
945
|
+
let raw = mxfp4_blocks(n_blocks, 11);
|
|
946
|
+
let op = MxFp4Deinterleave::new(32).unwrap();
|
|
947
|
+
|
|
948
|
+
let descs = op
|
|
949
|
+
.propagate_descriptors(&[raw_descriptor(raw.len())])
|
|
950
|
+
.unwrap();
|
|
951
|
+
let value_desc = descs[0].clone();
|
|
952
|
+
|
|
953
|
+
// One group per MXFP4 block is the whole premise of the codec.
|
|
954
|
+
assert_eq!(value_desc.length_bytes as usize, n_blocks * GROUP_SIZE);
|
|
955
|
+
|
|
956
|
+
let c = PerGroupCodebook;
|
|
957
|
+
assert!(
|
|
958
|
+
c.accepts(&value_desc),
|
|
959
|
+
"the codec must accept the plane its own producer emits: {value_desc:?}"
|
|
960
|
+
);
|
|
961
|
+
|
|
962
|
+
let planes = op
|
|
963
|
+
.forward(&[Plane::new(raw.clone(), raw_descriptor(raw.len())).unwrap()])
|
|
964
|
+
.unwrap();
|
|
965
|
+
let value_plane = planes[0].bytes.to_vec();
|
|
966
|
+
assert_eq!(value_plane.len(), n_blocks * GROUP_SIZE);
|
|
967
|
+
assert!(
|
|
968
|
+
value_plane.iter().all(|&b| b <= 0x0F),
|
|
969
|
+
"the value plane is one nibble per byte, so no byte exceeds 0x0F"
|
|
970
|
+
);
|
|
971
|
+
|
|
972
|
+
let enc = c.encode(&value_plane, None, &PlaneLayout::Flat).unwrap();
|
|
973
|
+
let dec = c
|
|
974
|
+
.decode(
|
|
975
|
+
enc.state_format_version,
|
|
976
|
+
&enc.state_bytes,
|
|
977
|
+
&enc.payload,
|
|
978
|
+
&PlaneLayout::Flat,
|
|
979
|
+
value_plane.len(),
|
|
980
|
+
)
|
|
981
|
+
.unwrap();
|
|
982
|
+
assert_eq!(
|
|
983
|
+
dec, value_plane,
|
|
984
|
+
"codec must be lossless on its own producer"
|
|
985
|
+
);
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
#[test]
|
|
989
|
+
fn codec_declines_a_genuinely_packed_plane_instead_of_halving_it() {
|
|
990
|
+
// Two values per byte. Reading this as one-nibble-per-byte would
|
|
991
|
+
// drop every high nibble, which is exactly the silent loss the
|
|
992
|
+
// `accepts` guard exists to prevent.
|
|
993
|
+
let mut d = raw_descriptor(64);
|
|
994
|
+
d.role = Role::Value {
|
|
995
|
+
format: crate::types::role::ValueFormat::Fp4E2m1,
|
|
996
|
+
};
|
|
997
|
+
d.element_width = ElementWidth::Nibble;
|
|
998
|
+
d.is_nibble_packed = true;
|
|
999
|
+
assert!(!PerGroupCodebook.accepts(&d));
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
#[test]
|
|
1003
|
+
fn codec_declines_a_length_that_is_not_whole_groups() {
|
|
1004
|
+
// Declined rather than failed in `encode`: packed FP4 has one
|
|
1005
|
+
// candidate chain, and a codec error drops the chain entirely.
|
|
1006
|
+
let mut d = raw_descriptor(GROUP_SIZE + 1);
|
|
1007
|
+
d.role = Role::Value {
|
|
1008
|
+
format: crate::types::role::ValueFormat::Fp4E2m1,
|
|
1009
|
+
};
|
|
1010
|
+
d.element_width = ElementWidth::Nibble;
|
|
1011
|
+
assert!(!PerGroupCodebook.accepts(&d));
|
|
1012
|
+
}
|
|
1013
|
+
}
|