pub struct Mxfp { /* private fields */ }Expand description
Quantization parameters for MXFP (OCP Microscaling) block quantization.
Each block of block_size consecutive elements along axis shares a single
float8_e8m0 exponent-only scale. The scale values are stored as raw bytes
in the buffer identified by scale_buffer_index.
The dequantization formula for element q with block index b and scale
byte e = scale[b] is:
s = 2^(e - 127) (float8_e8m0 shared exponent)
x_real = s * value_of(q) (float_value_of(q) or int_value_of(q))Unlike per-block affine, MXFP requires exact divisibility: shape[axis]
MUST be a positive multiple of block_size. No partial trailing blocks are
permitted.
§Wire format
Total descriptor length: 16 bytes (including the 4-byte header).
| Offset | Field | Type |
|---|---|---|
| 0 | scheme_tag | uint8 (must be 0x05) |
| 1 | scheme_version | uint8 (must be 0x01) |
| 2 | flags | uint16 LE (must be 0x0000) |
| 4 | axis | uint32 LE |
| 8 | block_size | uint32 LE, power-of-two in [16, 2048] |
| 12 | scale_buffer_index | uint32 LE |
§Design notes
PartialEq, Eq, and Hash are all derived because this struct contains
no floating-point fields — all fields are integers.
Copy because the struct is ≤ 24 bytes with no Drop glue.
§Examples
use hurray_core::Mxfp;
let q = Mxfp::new(0, 32, 1).unwrap();
assert_eq!(q.axis(), 0);
assert_eq!(q.block_size(), 32);
assert_eq!(q.scale_buffer_index(), 1);Implementations§
Source§impl Mxfp
impl Mxfp
Sourcepub fn new(axis: u32, block_size: u32, scale_buffer_index: u32) -> Result<Self>
pub fn new(axis: u32, block_size: u32, scale_buffer_index: u32) -> Result<Self>
Creates a new Mxfp descriptor.
§Errors
Error::InvalidBlockSize—block_sizeis not a power of two, or lies outside[MXFP_MIN_BLOCK_SIZE,MXFP_MAX_BLOCK_SIZE]([16, 2048]).
§Examples
use hurray_core::{Mxfp, Error};
assert!(Mxfp::new(0, 32, 1).is_ok());
assert!(Mxfp::new(0, 16, 1).is_ok());
assert!(Mxfp::new(0, 2048, 1).is_ok());
// block_size < 16 is rejected.
assert!(Mxfp::new(0, 8, 1).is_err());
// block_size > 2048 is rejected.
assert!(Mxfp::new(0, 4096, 1).is_err());
// Non-power-of-two is rejected.
assert!(Mxfp::new(0, 48, 1).is_err());Sourcepub fn axis(&self) -> u32
pub fn axis(&self) -> u32
Returns the quantization axis index.
§Examples
use hurray_core::Mxfp;
let q = Mxfp::new(2, 32, 1).unwrap();
assert_eq!(q.axis(), 2);Sourcepub fn block_size(&self) -> u32
pub fn block_size(&self) -> u32
Returns the number of logical elements per block along axis.
Always a power of two in [MXFP_MIN_BLOCK_SIZE, MXFP_MAX_BLOCK_SIZE].
§Examples
use hurray_core::Mxfp;
let q = Mxfp::new(0, 64, 1).unwrap();
assert_eq!(q.block_size(), 64);Sourcepub fn scale_buffer_index(&self) -> u32
pub fn scale_buffer_index(&self) -> u32
Returns the buffer table index of the per-block float8_e8m0 scale array.
§Examples
use hurray_core::Mxfp;
let q = Mxfp::new(0, 32, 3).unwrap();
assert_eq!(q.scale_buffer_index(), 3);Sourcepub fn num_blocks_per_axis(&self, shape_axis: u64) -> Result<u64>
pub fn num_blocks_per_axis(&self, shape_axis: u64) -> Result<u64>
Computes the number of blocks along axis for a given shape_axis size.
MXFP requires exact divisibility: shape_axis MUST be a positive multiple
of block_size. This is stricter than per-block affine, which uses
div_ceil and allows partial trailing blocks.
§Errors
Error::QuantizationShapeMismatch—shape_axisis not evenly divisible byblock_size.
§Examples
use hurray_core::Mxfp;
let q = Mxfp::new(0, 32, 1).unwrap();
assert_eq!(q.num_blocks_per_axis(64).unwrap(), 2);
assert_eq!(q.num_blocks_per_axis(32).unwrap(), 1);
// 65 is not a multiple of 32 — error.
assert!(q.num_blocks_per_axis(65).is_err());
// 0 is not a positive multiple — error.
assert!(q.num_blocks_per_axis(0).is_err());Sourcepub fn validate_against_shape_axis(&self, shape_axis: u64) -> Result<()>
pub fn validate_against_shape_axis(&self, shape_axis: u64) -> Result<()>
Validates that shape_axis satisfies the MXFP divisibility constraint.
shape_axis MUST be greater than zero AND evenly divisible by block_size.
§Errors
Error::QuantizationShapeMismatch—shape_axis == 0orshape_axis % block_size != 0.
§Examples
use hurray_core::Mxfp;
let q = Mxfp::new(0, 32, 1).unwrap();
assert!(q.validate_against_shape_axis(64).is_ok());
assert!(q.validate_against_shape_axis(32).is_ok());
// Zero is rejected (not a positive multiple).
assert!(q.validate_against_shape_axis(0).is_err());
// 65 is not divisible by 32.
assert!(q.validate_against_shape_axis(65).is_err());Sourcepub fn validate_scale_bytes(&self, bytes: &[u8]) -> Result<()>
pub fn validate_scale_bytes(&self, bytes: &[u8]) -> Result<()>
Validates the content of a scale buffer for MXFP conformance.
Per docs/spec/quantization/mxfp.md § Referenced Buffer: the bit patterns
0x00 and 0xFF are reserved (NaN per OCP MX v1.0 § 5.6) and MUST NOT
appear in any scale byte.
§Errors
Error::InvalidQuantization— any byte inbytesis0x00or0xFF.
§Examples
use hurray_core::Mxfp;
let q = Mxfp::new(0, 32, 1).unwrap();
// Valid scale bytes: non-zero, non-0xFF.
assert!(q.validate_scale_bytes(&[0x01, 0x7F, 0x80, 0xFE]).is_ok());
// 0x00 is forbidden.
assert!(q.validate_scale_bytes(&[0x01, 0x00, 0x7F]).is_err());
// 0xFF is forbidden.
assert!(q.validate_scale_bytes(&[0x7F, 0xFF]).is_err());Sourcepub fn valid_storage_types() -> &'static [ElementType]
pub fn valid_storage_types() -> &'static [ElementType]
Returns the set of storage ElementTypes that are valid for this scheme.
Per docs/spec/quantization/mxfp.md § Valid Storage Types.
WHY &'static [ElementType]: no allocation per call; slice::contains
over ≤10 items beats any hash structure (design decision #5).
§Examples
use hurray_core::{ElementType, Mxfp};
assert!(Mxfp::valid_storage_types().contains(&ElementType::Float8E4M3));
assert!(Mxfp::valid_storage_types().contains(&ElementType::Int8));
assert!(Mxfp::valid_storage_types().contains(&ElementType::Int4));
assert!(!Mxfp::valid_storage_types().contains(&ElementType::Float32));