use crate::dtype::{DType, is_reserved_dtype_token};
pub const SK4_DTYPE_TOKENS: [&str; 24] = [
"f16",
"bf16",
"f32",
"f64",
"i8",
"i16",
"u8",
"u16",
"i32",
"i64",
"u32",
"u64",
"bool",
"f8e4m3fn",
"f8e4m3fnuz",
"f8e5m2",
"f8e5m2fnuz",
"f8e8m0",
"f8e6m2",
"i4",
"u4",
"b1",
"c64",
"c128",
];
pub const RECOGNIZED_UNSUPPORTED_DTYPE_TOKENS: &[&str] =
&["u16", "u64", "i4", "u4", "b1", "c64", "c128"];
pub fn sk4_token(dt: DType) -> Option<&'static str> {
Some(match dt {
DType::F16 => "f16",
DType::BF16 => "bf16",
DType::F32 => "f32",
DType::F64 => "f64",
DType::I8 => "i8",
DType::I16 => "i16",
DType::U8 => "u8",
DType::U32 => "u32",
DType::I32 => "i32",
DType::I64 => "i64",
DType::F8E4M3 => "f8e4m3fn",
DType::F8E5M2 => "f8e5m2",
DType::F8E8M0 => "f8e8m0",
DType::F8E6M2 => "f8e6m2",
DType::Bool => "bool",
DType::F6E2M3 | DType::F6E3M2 | DType::F4 => return None,
})
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TokenKind {
Supported,
RecognizedUnsupported,
Reserved,
Unknown,
}
pub fn classify_dtype_token(token: &str) -> TokenKind {
if is_reserved_dtype_token(token) {
return TokenKind::Reserved;
}
if RECOGNIZED_UNSUPPORTED_DTYPE_TOKENS
.iter()
.any(|t| token.eq_ignore_ascii_case(t))
{
return TokenKind::RecognizedUnsupported;
}
if DType::ALL
.iter()
.filter_map(|d| sk4_token(*d))
.any(|t| token.eq_ignore_ascii_case(t))
{
return TokenKind::Supported;
}
TokenKind::Unknown
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dtype::RESERVED_DTYPE_TOKENS;
use std::collections::BTreeSet;
fn supported_set() -> BTreeSet<&'static str> {
DType::ALL.iter().filter_map(|d| sk4_token(*d)).collect()
}
#[test]
fn the_three_kinds_partition_the_sk4_vocabulary_exactly() {
let supported = supported_set();
let recognized: BTreeSet<&str> = RECOGNIZED_UNSUPPORTED_DTYPE_TOKENS
.iter()
.copied()
.collect();
let reserved: BTreeSet<&str> = RESERVED_DTYPE_TOKENS.iter().copied().collect();
assert_eq!(supported.len(), 15, "supported: {supported:?}");
assert_eq!(
recognized.len(),
7,
"recognized-unsupported: {recognized:?}"
);
assert_eq!(reserved.len(), 2, "reserved: {reserved:?}");
assert_eq!(
supported.len() + recognized.len() + reserved.len(),
SK4_DTYPE_TOKENS.len(),
"the three kinds must sum to the vocabulary — a mismatch means a \
token is unclassified or double-counted",
);
assert!(supported.is_disjoint(&recognized));
assert!(supported.is_disjoint(&reserved));
assert!(recognized.is_disjoint(&reserved));
let union: BTreeSet<&str> = supported
.union(&recognized)
.copied()
.collect::<BTreeSet<_>>()
.union(&reserved)
.copied()
.collect();
let vocabulary: BTreeSet<&str> = SK4_DTYPE_TOKENS.iter().copied().collect();
assert_eq!(
union, vocabulary,
"the three kinds must cover the sk4 vocabulary exactly",
);
assert_eq!(vocabulary.len(), 24, "sk4 tokens must be distinct");
}
#[test]
fn every_fuel_dtype_either_has_a_seam_token_or_is_outside_the_vocabulary() {
let with = DType::ALL
.iter()
.filter(|d| sk4_token(**d).is_some())
.count();
let without = DType::ALL
.iter()
.filter(|d| sk4_token(**d).is_none())
.count();
assert_eq!(with, 15);
assert_eq!(without, 3, "the block-scoped sub-byte element formats");
assert_eq!(with + without, DType::ALL.len());
for dt in DType::ALL {
if let Some(tok) = sk4_token(*dt) {
assert!(
SK4_DTYPE_TOKENS.contains(&tok),
"{dt:?} emits {tok:?}, which is not an sk4 token",
);
}
}
}
#[test]
fn the_seam_spelling_differs_from_the_internal_one_for_fp8_e4m3() {
assert_eq!(sk4_token(DType::F8E4M3), Some("f8e4m3fn"));
assert_eq!(DType::F8E4M3.as_str(), "f8e4m3");
assert_eq!(sk4_token(DType::F8E5M2), Some("f8e5m2"));
assert_eq!(DType::F8E5M2.as_str(), "f8e5m2");
}
#[test]
fn classify_covers_all_four_kinds_and_resists_the_prefix_trap() {
assert_eq!(classify_dtype_token("f32"), TokenKind::Supported);
assert_eq!(classify_dtype_token("f8e4m3fn"), TokenKind::Supported);
assert_eq!(classify_dtype_token("bool"), TokenKind::Supported);
assert_eq!(
classify_dtype_token("c128"),
TokenKind::RecognizedUnsupported
);
assert_eq!(classify_dtype_token("f8e5m2fnuz"), TokenKind::Reserved);
assert_eq!(classify_dtype_token("asdf"), TokenKind::Unknown);
assert_eq!(classify_dtype_token("f8e5m2"), TokenKind::Supported);
assert_eq!(classify_dtype_token("f8e5m2fnuz"), TokenKind::Reserved);
assert_eq!(classify_dtype_token("f8e4m3"), TokenKind::Unknown);
assert_eq!(classify_dtype_token("F32"), TokenKind::Supported);
assert_eq!(classify_dtype_token("F8E5M2FNUZ"), TokenKind::Reserved);
}
#[test]
fn classification_is_total_over_the_vocabulary() {
for tok in SK4_DTYPE_TOKENS {
assert_ne!(
classify_dtype_token(tok),
TokenKind::Unknown,
"{tok} is in the sk4 vocabulary and must not classify as Unknown",
);
}
assert_eq!(
classify_dtype_token("definitely-not-a-dtype"),
TokenKind::Unknown
);
}
}