1use crate::error::Result;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33pub enum GgmlDType {
34 F32,
35 F16,
36 BF16,
37 Q4_0,
38 Q4_1,
39 Q5_0,
40 Q5_1,
41 Q8_0,
42 Q8_1,
43 Q2K,
44 Q3K,
45 Q4K,
46 Q5K,
47 Q6K,
48 Q8K,
49}
50
51impl GgmlDType {
52 pub fn from_u32(u: u32) -> Result<Self> {
53 let dtype = match u {
54 0 => Self::F32,
55 1 => Self::F16,
56 2 => Self::Q4_0,
57 3 => Self::Q4_1,
58 6 => Self::Q5_0,
59 7 => Self::Q5_1,
60 8 => Self::Q8_0,
61 9 => Self::Q8_1,
62 10 => Self::Q2K,
63 11 => Self::Q3K,
64 12 => Self::Q4K,
65 13 => Self::Q5K,
66 14 => Self::Q6K,
67 15 => Self::Q8K,
68 30 => Self::BF16,
69 _ => return Err(crate::Error::Msg(format!("unknown dtype for tensor {u}")).bt()),
70 };
71 Ok(dtype)
72 }
73
74 pub fn to_u32(self) -> u32 {
75 match self {
76 Self::F32 => 0,
77 Self::F16 => 1,
78 Self::Q4_0 => 2,
79 Self::Q4_1 => 3,
80 Self::Q5_0 => 6,
81 Self::Q5_1 => 7,
82 Self::Q8_0 => 8,
83 Self::Q8_1 => 9,
84 Self::Q2K => 10,
85 Self::Q3K => 11,
86 Self::Q4K => 12,
87 Self::Q5K => 13,
88 Self::Q6K => 14,
89 Self::Q8K => 15,
90 Self::BF16 => 30,
91 }
92 }
93
94 pub fn type_size(&self) -> usize {
95 match self {
96 Self::F32 => 4,
97 Self::F16 | Self::BF16 => 2,
98 Self::Q4_0 => 18, Self::Q4_1 => 20, Self::Q5_0 => 22, Self::Q5_1 => 24, Self::Q8_0 => 34, Self::Q8_1 => 36, Self::Q2K => 84, Self::Q3K => 110, Self::Q4K => 144, Self::Q5K => 176, Self::Q6K => 210, Self::Q8K => 292, }
112 }
113
114 pub fn block_size(&self) -> usize {
115 match self {
116 Self::F32 | Self::F16 | Self::BF16 => 1,
117 Self::Q4_0 | Self::Q4_1 | Self::Q5_0 | Self::Q5_1 | Self::Q8_0 | Self::Q8_1 => 32,
118 Self::Q2K | Self::Q3K | Self::Q4K | Self::Q5K | Self::Q6K | Self::Q8K => 256,
119 }
120 }
121
122 pub fn check_dequant_count(self, op_label: &str, numel: usize, byte_len: usize) -> Result<()> {
129 let block = self.block_size();
130 if !numel.is_multiple_of(block) {
131 return Err(crate::Error::Msg(format!(
132 "{op_label}: element count {numel} is not a multiple of {self:?}'s block size {block}",
133 ))
134 .bt());
135 }
136 match (numel / block).checked_mul(self.type_size()) {
137 Some(need) if need <= byte_len => Ok(()),
138 Some(need) => Err(crate::Error::Msg(format!(
139 "{op_label}: {numel} elements need {need} bytes of {self:?} blocks, but the \
140 buffer holds {byte_len}",
141 ))
142 .bt()),
143 None => Err(crate::Error::Msg(format!(
144 "{op_label}: {numel} {self:?} elements overflow a byte count"
145 ))
146 .bt()),
147 }
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::GgmlDType;
154
155 #[track_caller]
156 fn declined(dtype: GgmlDType, numel: usize, byte_len: usize, needle: &str) {
157 let msg = dtype
158 .check_dequant_count("t", numel, byte_len)
159 .expect_err("expected a decline")
160 .to_string();
161 assert!(msg.contains(needle), "wrong decline: {msg}");
162 }
163
164 #[test]
165 fn whole_blocks_that_fit_are_accepted() {
166 GgmlDType::Q4_0.check_dequant_count("t", 64, 36).unwrap();
168 GgmlDType::Q4K.check_dequant_count("t", 256, 144).unwrap();
169 GgmlDType::F32.check_dequant_count("t", 3, 12).unwrap();
170 GgmlDType::Q4_0.check_dequant_count("t", 0, 0).unwrap();
171 }
172
173 #[test]
174 fn a_partial_block_is_declined() {
175 declined(
176 GgmlDType::Q4_0,
177 65,
178 1_000,
179 "element count 65 is not a multiple of Q4_0's block size 32",
180 );
181 declined(
182 GgmlDType::Q4K,
183 128,
184 1_000,
185 "element count 128 is not a multiple of Q4K's block size 256",
186 );
187 }
188
189 #[test]
190 fn blocks_one_byte_past_the_buffer_are_declined() {
191 declined(
192 GgmlDType::Q4_0,
193 64,
194 35,
195 "64 elements need 36 bytes of Q4_0 blocks, but the buffer holds 35",
196 );
197 declined(
198 GgmlDType::F16,
199 3,
200 5,
201 "3 elements need 6 bytes of F16 blocks",
202 );
203 GgmlDType::F16.check_dequant_count("t", 3, 6).unwrap();
204 }
205
206 #[test]
207 fn an_overflowing_count_is_a_typed_error() {
208 declined(
209 GgmlDType::F32,
210 usize::MAX,
211 usize::MAX,
212 "overflow a byte count",
213 );
214 }
215}