use crate::block_layout::BlockLayout;
use crate::float_layout::FloatLayout;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Codec {
Q4K,
Q5K,
Q6K,
Q8_0,
Q3K,
Q4_0,
Float16,
BFloat16,
Q2K,
Q5_1,
Q5_0,
Q4_1,
Q8_1,
Q8K,
Iq1S,
Iq1M,
Iq2Xxs,
Iq2Xs,
Iq2S,
Iq3Xxs,
Iq3S,
Iq4Nl,
Iq4Xs,
Tq10,
Tq20,
Mxfp4,
Nvfp4,
Q1_0,
Q2_0,
BFloat8,
Bf8E5M2,
Bf4E2M1,
Fp6E3M2,
}
impl Codec {
#[must_use]
pub fn tag(self) -> u8 {
match self {
Codec::Q2K => 0,
Codec::Q3K => 1,
Codec::Q4K => 2,
Codec::Q5K => 3,
Codec::Q6K => 4,
Codec::Q8_0 => 5,
Codec::Q4_0 => 6,
Codec::Float16 => 7,
Codec::BFloat16 => 8,
Codec::Q5_1 => 9,
Codec::Q5_0 => 10,
Codec::Q4_1 => 11,
Codec::Q8_1 => 12,
Codec::Q8K => 13,
Codec::Iq1S => 14,
Codec::Iq1M => 15,
Codec::Iq2Xxs => 16,
Codec::Iq2Xs => 17,
Codec::Iq2S => 18,
Codec::Iq3Xxs => 19,
Codec::Iq3S => 20,
Codec::Iq4Nl => 21,
Codec::Iq4Xs => 22,
Codec::Tq10 => 23,
Codec::Tq20 => 24,
Codec::Mxfp4 => 25,
Codec::Nvfp4 => 26,
Codec::Q1_0 => 27,
Codec::Q2_0 => 28,
Codec::BFloat8 => 29,
Codec::Bf8E5M2 => 30,
Codec::Bf4E2M1 => 31,
Codec::Fp6E3M2 => 32,
}
}
#[must_use]
pub fn from_tag(tag: u8) -> Option<Self> {
match tag {
0 => Some(Codec::Q2K),
1 => Some(Codec::Q3K),
2 => Some(Codec::Q4K),
3 => Some(Codec::Q5K),
4 => Some(Codec::Q6K),
5 => Some(Codec::Q8_0),
6 => Some(Codec::Q4_0),
7 => Some(Codec::Float16),
8 => Some(Codec::BFloat16),
9 => Some(Codec::Q5_1),
10 => Some(Codec::Q5_0),
11 => Some(Codec::Q4_1),
12 => Some(Codec::Q8_1),
13 => Some(Codec::Q8K),
14 => Some(Codec::Iq1S),
15 => Some(Codec::Iq1M),
16 => Some(Codec::Iq2Xxs),
17 => Some(Codec::Iq2Xs),
18 => Some(Codec::Iq2S),
19 => Some(Codec::Iq3Xxs),
20 => Some(Codec::Iq3S),
21 => Some(Codec::Iq4Nl),
22 => Some(Codec::Iq4Xs),
23 => Some(Codec::Tq10),
24 => Some(Codec::Tq20),
25 => Some(Codec::Mxfp4),
26 => Some(Codec::Nvfp4),
27 => Some(Codec::Q1_0),
28 => Some(Codec::Q2_0),
29 => Some(Codec::BFloat8),
30 => Some(Codec::Bf8E5M2),
31 => Some(Codec::Bf4E2M1),
32 => Some(Codec::Fp6E3M2),
_ => None,
}
}
pub const FP6_E3M2_BLOCK_ELEMENTS: usize = 32;
pub const FP6_E3M2_BLOCK_BYTES: usize =
Self::FP6_E3M2_BLOCK_ELEMENTS * FloatLayout::E3M2.width() as usize / 8 + 2;
#[must_use]
pub const fn block_layout(self) -> Option<BlockLayout> {
match self {
Codec::Q4_0 => Some(BlockLayout::Q4_0),
Codec::Q4_1 => Some(BlockLayout::Q4_1),
Codec::Q5_0 => Some(BlockLayout::Q5_0),
Codec::Q5_1 => Some(BlockLayout::Q5_1),
Codec::Q8_0 => Some(BlockLayout::Q8_0),
Codec::Q8_1 => Some(BlockLayout::Q8_1),
Codec::Q1_0 => Some(BlockLayout::Q1_0),
Codec::Q2_0 => Some(BlockLayout::Q2_0),
Codec::Q2K => Some(BlockLayout::Q2_K),
Codec::Q3K => Some(BlockLayout::Q3_K),
Codec::Q4K => Some(BlockLayout::Q4_K),
Codec::Q5K => Some(BlockLayout::Q5_K),
Codec::Q6K => Some(BlockLayout::Q6_K),
Codec::Q8K => Some(BlockLayout::Q8_K),
_ => None,
}
}
#[must_use]
pub const fn layout(self) -> Option<FloatLayout> {
match self {
Codec::Float16 => Some(FloatLayout::F16),
Codec::BFloat16 => Some(FloatLayout::BF16),
Codec::BFloat8 => Some(FloatLayout::E5M2),
Codec::Bf8E5M2 => Some(FloatLayout::E5M2_SATURATING),
Codec::Bf4E2M1 => Some(FloatLayout::E2M1),
Codec::Fp6E3M2 => Some(FloatLayout::E3M2),
Codec::Q4K
| Codec::Q5K
| Codec::Q6K
| Codec::Q8_0
| Codec::Q3K
| Codec::Q4_0
| Codec::Q2K
| Codec::Q5_1
| Codec::Q5_0
| Codec::Q4_1
| Codec::Q8_1
| Codec::Q8K
| Codec::Iq1S
| Codec::Iq1M
| Codec::Iq2Xxs
| Codec::Iq2Xs
| Codec::Iq2S
| Codec::Iq3Xxs
| Codec::Iq3S
| Codec::Iq4Nl
| Codec::Iq4Xs
| Codec::Tq10
| Codec::Tq20
| Codec::Mxfp4
| Codec::Nvfp4
| Codec::Q1_0
| Codec::Q2_0 => None,
}
}
}
#[cfg(test)]
mod tests {
use super::Codec;
#[test]
fn card_02_bf8_codec_round_trips_all_stable_tags() {
let variants = [
(Codec::Q2K, 0),
(Codec::Q3K, 1),
(Codec::Q4K, 2),
(Codec::Q5K, 3),
(Codec::Q6K, 4),
(Codec::Q8_0, 5),
(Codec::Q4_0, 6),
(Codec::Float16, 7),
(Codec::BFloat16, 8),
(Codec::Q5_1, 9),
(Codec::Q5_0, 10),
(Codec::Q4_1, 11),
(Codec::Q8_1, 12),
(Codec::Q8K, 13),
(Codec::Iq1S, 14),
(Codec::Iq1M, 15),
(Codec::Iq2Xxs, 16),
(Codec::Iq2Xs, 17),
(Codec::Iq2S, 18),
(Codec::Iq3Xxs, 19),
(Codec::Iq3S, 20),
(Codec::Iq4Nl, 21),
(Codec::Iq4Xs, 22),
(Codec::Tq10, 23),
(Codec::Tq20, 24),
(Codec::Mxfp4, 25),
(Codec::Nvfp4, 26),
(Codec::Q1_0, 27),
(Codec::Q2_0, 28),
(Codec::BFloat8, 29),
(Codec::Bf8E5M2, 30),
(Codec::Bf4E2M1, 31),
(Codec::Fp6E3M2, 32),
];
assert_eq!(variants.len(), 33);
for (codec, stable_tag) in variants {
assert_eq!(codec.tag(), stable_tag);
assert_eq!(Codec::from_tag(stable_tag), Some(codec));
}
}
#[test]
fn fp6_e3m2_codec_tag_32_round_trip() {
assert_eq!(Codec::Fp6E3M2.tag(), 32);
assert_eq!(Codec::from_tag(32), Some(Codec::Fp6E3M2));
}
#[test]
fn fp6_e3m2_codec_tag_33_rejected() {
assert_eq!(Codec::from_tag(33), None);
}
#[test]
fn fp6_e3m2_codec_block_geometry_26_bytes_32_elements() {
assert_eq!(Codec::FP6_E3M2_BLOCK_BYTES, 26);
assert_eq!(Codec::FP6_E3M2_BLOCK_ELEMENTS, 32);
}
#[test]
fn card_02_bf8_codec_rejects_unassigned_tag() {
assert_eq!(Codec::from_tag(33), None);
assert_eq!(Codec::from_tag(255), None);
}
}