1use hurray_core::{
14 descriptor::{ExtensionTypeDescriptor, ShardDescriptor, Statistics, TensorDescriptor},
15 QuantizationDescriptor,
16};
17
18use super::{HurrayDescriptorField, U64Source};
19use crate::status::{
20 status_from_core_error, HurrayStatus, HURRAY_ERR_FIELD_NOT_APPLICABLE,
21 HURRAY_ERR_FIELD_NOT_PRESENT, HURRAY_ERR_INDEX_OUT_OF_BOUNDS,
22};
23
24pub const HURRAY_QUANT_FIELD_SCHEME_TAG: HurrayDescriptorField = 0x0002_0000;
34
35pub const HURRAY_QUANT_FIELD_PER_TENSOR_SCALE: HurrayDescriptorField = 0x0002_0100;
37
38pub const HURRAY_QUANT_FIELD_PER_TENSOR_ZERO_POINT: HurrayDescriptorField = 0x0002_0101;
40
41pub const HURRAY_QUANT_FIELD_PER_CHANNEL_AXIS: HurrayDescriptorField = 0x0002_0200;
43
44pub const HURRAY_QUANT_FIELD_PER_CHANNEL_SCALE_BUFFER: HurrayDescriptorField = 0x0002_0201;
46
47pub const HURRAY_QUANT_FIELD_PER_CHANNEL_ZERO_POINT_BUFFER: HurrayDescriptorField = 0x0002_0202;
50
51pub const HURRAY_QUANT_FIELD_PER_CHANNEL_SCALE_TYPE: HurrayDescriptorField = 0x0002_0203;
53
54pub const HURRAY_QUANT_FIELD_PER_BLOCK_AXIS: HurrayDescriptorField = 0x0002_0300;
56
57pub const HURRAY_QUANT_FIELD_PER_BLOCK_BLOCK_SIZE: HurrayDescriptorField = 0x0002_0301;
59
60pub const HURRAY_QUANT_FIELD_PER_BLOCK_SCALE_BUFFER: HurrayDescriptorField = 0x0002_0302;
62
63pub const HURRAY_QUANT_FIELD_PER_BLOCK_ZERO_POINT_BUFFER: HurrayDescriptorField = 0x0002_0303;
66
67pub const HURRAY_QUANT_FIELD_PER_BLOCK_SCALE_TYPE: HurrayDescriptorField = 0x0002_0304;
69
70pub const HURRAY_QUANT_FIELD_NF4_AXIS: HurrayDescriptorField = 0x0002_0400;
72
73pub const HURRAY_QUANT_FIELD_NF4_BLOCK_SIZE: HurrayDescriptorField = 0x0002_0401;
75
76pub const HURRAY_QUANT_FIELD_NF4_SCALE_BUFFER: HurrayDescriptorField = 0x0002_0402;
78
79pub const HURRAY_QUANT_FIELD_MXFP_AXIS: HurrayDescriptorField = 0x0002_0500;
81
82pub const HURRAY_QUANT_FIELD_MXFP_BLOCK_SIZE: HurrayDescriptorField = 0x0002_0501;
84
85pub const HURRAY_QUANT_FIELD_MXFP_SCALE_BUFFER: HurrayDescriptorField = 0x0002_0502;
87
88pub const HURRAY_STATS_FIELD_COMPUTED_MASK: HurrayDescriptorField = 0x0003_0000;
92
93pub const HURRAY_STATS_FIELD_NNZ: HurrayDescriptorField = 0x0003_0001;
95
96pub const HURRAY_STATS_FIELD_SPARSITY_RATIO: HurrayDescriptorField = 0x0003_0002;
98
99pub const HURRAY_STATS_FIELD_VALUE_MIN: HurrayDescriptorField = 0x0003_0003;
101
102pub const HURRAY_STATS_FIELD_VALUE_MAX: HurrayDescriptorField = 0x0003_0004;
104
105pub const HURRAY_STATS_FIELD_VALUE_ABS_MAX: HurrayDescriptorField = 0x0003_0005;
107
108pub const HURRAY_STATS_FIELD_VALUE_MEAN: HurrayDescriptorField = 0x0003_0006;
110
111pub const HURRAY_STATS_FIELD_VALUE_STDDEV: HurrayDescriptorField = 0x0003_0007;
113
114pub const HURRAY_STATS_FIELD_NM_N: HurrayDescriptorField = 0x0003_0008;
116
117pub const HURRAY_STATS_FIELD_NM_M: HurrayDescriptorField = 0x0003_0009;
119
120pub const HURRAY_STATS_FIELD_HAS_NAN: HurrayDescriptorField = 0x0003_000A;
122
123pub const HURRAY_STATS_FIELD_HAS_INF: HurrayDescriptorField = 0x0003_000B;
125
126pub const HURRAY_SHARD_FIELD_PARENT_SHAPE: HurrayDescriptorField = 0x0004_0000;
130
131pub const HURRAY_SHARD_FIELD_SHARD_OFFSET: HurrayDescriptorField = 0x0004_0001;
134
135pub const HURRAY_EXT_TYPE_FIELD_BIT_WIDTH: HurrayDescriptorField = 0x0005_0000;
139
140pub const HURRAY_EXT_TYPE_FIELD_PACKING_FACTOR: HurrayDescriptorField = 0x0005_0001;
142
143pub const HURRAY_EXT_TYPE_FIELD_IS_FLOAT: HurrayDescriptorField = 0x0005_0002;
145
146pub const HURRAY_EXT_TYPE_FIELD_IS_SIGNED: HurrayDescriptorField = 0x0005_0003;
148
149pub const HURRAY_EXT_TYPE_FIELD_SIGN_BITS: HurrayDescriptorField = 0x0005_0004;
151
152pub const HURRAY_EXT_TYPE_FIELD_EXPONENT_BITS: HurrayDescriptorField = 0x0005_0005;
154
155pub const HURRAY_EXT_TYPE_FIELD_MANTISSA_BITS: HurrayDescriptorField = 0x0005_0006;
157
158pub const HURRAY_EXT_TYPE_FIELD_EXPONENT_BIAS: HurrayDescriptorField = 0x0005_0007;
160
161pub const HURRAY_EXT_TYPE_FIELD_HAS_NAN: HurrayDescriptorField = 0x0005_0008;
163
164pub const HURRAY_EXT_TYPE_FIELD_HAS_INF: HurrayDescriptorField = 0x0005_0009;
166
167pub const HURRAY_COMPOSITE_MEMBER_FIELD_ROLE: HurrayDescriptorField = 0x0006_0000;
172
173fn check_level(level: u32) -> Result<(), HurrayStatus> {
180 if level != 0 {
181 return Err(HURRAY_ERR_INDEX_OUT_OF_BOUNDS);
182 }
183 Ok(())
184}
185
186fn quantization(desc: &TensorDescriptor) -> Result<QuantizationDescriptor, HurrayStatus> {
195 let bytes = desc
196 .quantization
197 .as_deref()
198 .ok_or(HURRAY_ERR_FIELD_NOT_PRESENT)?;
199 QuantizationDescriptor::decode(bytes)
200 .map(|(q, _)| q)
201 .map_err(|e| status_from_core_error(&e))
202}
203
204fn statistics(desc: &TensorDescriptor) -> Result<&Statistics, HurrayStatus> {
206 desc.statistics.as_ref().ok_or(HURRAY_ERR_FIELD_NOT_PRESENT)
207}
208
209fn shard(desc: &TensorDescriptor) -> Result<&ShardDescriptor, HurrayStatus> {
211 desc.shard.as_ref().ok_or(HURRAY_ERR_FIELD_NOT_PRESENT)
212}
213
214fn ext_type(desc: &TensorDescriptor) -> Result<&ExtensionTypeDescriptor, HurrayStatus> {
216 desc.extension_type
217 .as_ref()
218 .ok_or(HURRAY_ERR_FIELD_NOT_PRESENT)
219}
220
221fn guarded<T>(valid: bool, value: T) -> Result<T, HurrayStatus> {
229 if valid {
230 Ok(value)
231 } else {
232 Err(HURRAY_ERR_FIELD_NOT_PRESENT)
233 }
234}
235
236pub(super) fn u64_scalar(
238 desc: &TensorDescriptor,
239 field: HurrayDescriptorField,
240 level: u32,
241) -> Result<u64, HurrayStatus> {
242 check_level(level)?;
243
244 match field {
245 HURRAY_QUANT_FIELD_SCHEME_TAG => Ok(u64::from(quantization(desc)?.scheme_tag().tag())),
247 HURRAY_QUANT_FIELD_PER_CHANNEL_AXIS
248 | HURRAY_QUANT_FIELD_PER_CHANNEL_SCALE_BUFFER
249 | HURRAY_QUANT_FIELD_PER_CHANNEL_ZERO_POINT_BUFFER
250 | HURRAY_QUANT_FIELD_PER_CHANNEL_SCALE_TYPE
251 | HURRAY_QUANT_FIELD_PER_BLOCK_AXIS
252 | HURRAY_QUANT_FIELD_PER_BLOCK_BLOCK_SIZE
253 | HURRAY_QUANT_FIELD_PER_BLOCK_SCALE_BUFFER
254 | HURRAY_QUANT_FIELD_PER_BLOCK_ZERO_POINT_BUFFER
255 | HURRAY_QUANT_FIELD_PER_BLOCK_SCALE_TYPE
256 | HURRAY_QUANT_FIELD_NF4_AXIS
257 | HURRAY_QUANT_FIELD_NF4_BLOCK_SIZE
258 | HURRAY_QUANT_FIELD_NF4_SCALE_BUFFER
259 | HURRAY_QUANT_FIELD_MXFP_AXIS
260 | HURRAY_QUANT_FIELD_MXFP_BLOCK_SIZE
261 | HURRAY_QUANT_FIELD_MXFP_SCALE_BUFFER => quant_u64(&quantization(desc)?, field),
262
263 HURRAY_STATS_FIELD_COMPUTED_MASK => Ok(u64::from(statistics(desc)?.computed_mask.0)),
265 HURRAY_STATS_FIELD_NNZ => {
266 let s = statistics(desc)?;
267 guarded(s.computed_mask.nnz_valid(), s.nnz)
268 }
269 HURRAY_STATS_FIELD_NM_N => {
270 let s = statistics(desc)?;
271 guarded(s.computed_mask.nm_sparsity_valid(), u64::from(s.nm_n))
272 }
273 HURRAY_STATS_FIELD_NM_M => {
274 let s = statistics(desc)?;
275 guarded(s.computed_mask.nm_sparsity_valid(), u64::from(s.nm_m))
276 }
277 HURRAY_STATS_FIELD_HAS_NAN => {
278 let s = statistics(desc)?;
279 guarded(s.computed_mask.nan_inf_valid(), u64::from(s.has_nan))
280 }
281 HURRAY_STATS_FIELD_HAS_INF => {
282 let s = statistics(desc)?;
283 guarded(s.computed_mask.nan_inf_valid(), u64::from(s.has_inf))
284 }
285
286 HURRAY_EXT_TYPE_FIELD_BIT_WIDTH => Ok(u64::from(ext_type(desc)?.bit_width)),
288 HURRAY_EXT_TYPE_FIELD_PACKING_FACTOR => Ok(u64::from(ext_type(desc)?.packing_factor)),
289 HURRAY_EXT_TYPE_FIELD_IS_FLOAT => Ok(u64::from(ext_type(desc)?.is_float)),
290 HURRAY_EXT_TYPE_FIELD_IS_SIGNED => Ok(u64::from(ext_type(desc)?.is_signed)),
291 HURRAY_EXT_TYPE_FIELD_SIGN_BITS => Ok(u64::from(ext_type(desc)?.sign_bits)),
292 HURRAY_EXT_TYPE_FIELD_EXPONENT_BITS => Ok(u64::from(ext_type(desc)?.exponent_bits)),
293 HURRAY_EXT_TYPE_FIELD_MANTISSA_BITS => Ok(u64::from(ext_type(desc)?.mantissa_bits)),
294 HURRAY_EXT_TYPE_FIELD_EXPONENT_BIAS => Ok(u64::from(ext_type(desc)?.exponent_bias)),
295 HURRAY_EXT_TYPE_FIELD_HAS_NAN => Ok(u64::from(ext_type(desc)?.has_nan)),
296 HURRAY_EXT_TYPE_FIELD_HAS_INF => Ok(u64::from(ext_type(desc)?.has_inf)),
297
298 HURRAY_COMPOSITE_MEMBER_FIELD_ROLE => desc
300 .composite_member
301 .as_ref()
302 .map(|cm| u64::from(cm.member_role.wire_byte()))
303 .ok_or(HURRAY_ERR_FIELD_NOT_PRESENT),
304
305 _ => Err(HURRAY_ERR_FIELD_NOT_APPLICABLE),
306 }
307}
308
309fn quant_u64(
315 q: &QuantizationDescriptor,
316 field: HurrayDescriptorField,
317) -> Result<u64, HurrayStatus> {
318 match (field, q) {
319 (HURRAY_QUANT_FIELD_PER_CHANNEL_AXIS, QuantizationDescriptor::PerChannelAffine(s)) => {
321 Ok(u64::from(s.axis()))
322 }
323 (
324 HURRAY_QUANT_FIELD_PER_CHANNEL_SCALE_BUFFER,
325 QuantizationDescriptor::PerChannelAffine(s),
326 ) => Ok(u64::from(s.scale_buffer_index())),
327 (
328 HURRAY_QUANT_FIELD_PER_CHANNEL_ZERO_POINT_BUFFER,
329 QuantizationDescriptor::PerChannelAffine(s),
330 ) => s
331 .zero_point_buffer_index()
332 .map(u64::from)
333 .ok_or(HURRAY_ERR_FIELD_NOT_PRESENT),
334 (
335 HURRAY_QUANT_FIELD_PER_CHANNEL_SCALE_TYPE,
336 QuantizationDescriptor::PerChannelAffine(s),
337 ) => Ok(u64::from(s.scale_type().tag())),
338
339 (HURRAY_QUANT_FIELD_PER_BLOCK_AXIS, QuantizationDescriptor::PerBlockAffine(s)) => {
341 Ok(u64::from(s.axis()))
342 }
343 (HURRAY_QUANT_FIELD_PER_BLOCK_BLOCK_SIZE, QuantizationDescriptor::PerBlockAffine(s)) => {
344 Ok(u64::from(s.block_size()))
345 }
346 (HURRAY_QUANT_FIELD_PER_BLOCK_SCALE_BUFFER, QuantizationDescriptor::PerBlockAffine(s)) => {
347 Ok(u64::from(s.scale_buffer_index()))
348 }
349 (
350 HURRAY_QUANT_FIELD_PER_BLOCK_ZERO_POINT_BUFFER,
351 QuantizationDescriptor::PerBlockAffine(s),
352 ) => s
353 .zero_point_buffer_index()
354 .map(u64::from)
355 .ok_or(HURRAY_ERR_FIELD_NOT_PRESENT),
356 (HURRAY_QUANT_FIELD_PER_BLOCK_SCALE_TYPE, QuantizationDescriptor::PerBlockAffine(s)) => {
357 Ok(u64::from(s.scale_type().tag()))
358 }
359
360 (HURRAY_QUANT_FIELD_NF4_AXIS, QuantizationDescriptor::Nf4(s)) => Ok(u64::from(s.axis())),
362 (HURRAY_QUANT_FIELD_NF4_BLOCK_SIZE, QuantizationDescriptor::Nf4(s)) => {
363 Ok(u64::from(s.block_size()))
364 }
365 (HURRAY_QUANT_FIELD_NF4_SCALE_BUFFER, QuantizationDescriptor::Nf4(s)) => {
366 Ok(u64::from(s.scale_buffer_index()))
367 }
368
369 (HURRAY_QUANT_FIELD_MXFP_AXIS, QuantizationDescriptor::Mxfp(s)) => Ok(u64::from(s.axis())),
371 (HURRAY_QUANT_FIELD_MXFP_BLOCK_SIZE, QuantizationDescriptor::Mxfp(s)) => {
372 Ok(u64::from(s.block_size()))
373 }
374 (HURRAY_QUANT_FIELD_MXFP_SCALE_BUFFER, QuantizationDescriptor::Mxfp(s)) => {
375 Ok(u64::from(s.scale_buffer_index()))
376 }
377
378 _ => Err(HURRAY_ERR_FIELD_NOT_APPLICABLE),
379 }
380}
381
382pub(super) fn i64_scalar(
384 desc: &TensorDescriptor,
385 field: HurrayDescriptorField,
386 level: u32,
387) -> Result<i64, HurrayStatus> {
388 check_level(level)?;
389
390 match field {
391 HURRAY_QUANT_FIELD_PER_TENSOR_ZERO_POINT => match quantization(desc)? {
392 QuantizationDescriptor::PerTensorAffine(s) => Ok(i64::from(s.zero_point())),
393 _ => Err(HURRAY_ERR_FIELD_NOT_APPLICABLE),
394 },
395 _ => Err(HURRAY_ERR_FIELD_NOT_APPLICABLE),
396 }
397}
398
399pub(super) fn f64_scalar(
401 desc: &TensorDescriptor,
402 field: HurrayDescriptorField,
403 level: u32,
404) -> Result<f64, HurrayStatus> {
405 check_level(level)?;
406
407 match field {
408 HURRAY_QUANT_FIELD_PER_TENSOR_SCALE => match quantization(desc)? {
409 QuantizationDescriptor::PerTensorAffine(s) => Ok(f64::from(s.scale())),
410 _ => Err(HURRAY_ERR_FIELD_NOT_APPLICABLE),
411 },
412
413 HURRAY_STATS_FIELD_SPARSITY_RATIO => {
414 let s = statistics(desc)?;
415 guarded(s.computed_mask.sparsity_valid(), s.sparsity_ratio)
416 }
417 HURRAY_STATS_FIELD_VALUE_MIN => {
418 let s = statistics(desc)?;
419 guarded(s.computed_mask.value_range_valid(), s.value_min)
420 }
421 HURRAY_STATS_FIELD_VALUE_MAX => {
422 let s = statistics(desc)?;
423 guarded(s.computed_mask.value_range_valid(), s.value_max)
424 }
425 HURRAY_STATS_FIELD_VALUE_ABS_MAX => {
426 let s = statistics(desc)?;
427 guarded(s.computed_mask.value_range_valid(), s.value_abs_max)
428 }
429 HURRAY_STATS_FIELD_VALUE_MEAN => {
430 let s = statistics(desc)?;
431 guarded(s.computed_mask.value_stats_valid(), s.value_mean)
432 }
433 HURRAY_STATS_FIELD_VALUE_STDDEV => {
434 let s = statistics(desc)?;
435 guarded(s.computed_mask.value_stats_valid(), s.value_stddev)
436 }
437
438 _ => Err(HURRAY_ERR_FIELD_NOT_APPLICABLE),
439 }
440}
441
442pub(super) fn u64_array<'a>(
444 desc: &'a TensorDescriptor,
445 field: HurrayDescriptorField,
446 level: u32,
447) -> Result<U64Source<'a>, HurrayStatus> {
448 check_level(level)?;
449
450 match field {
451 HURRAY_SHARD_FIELD_PARENT_SHAPE => Ok(U64Source::Direct(&shard(desc)?.parent_shape)),
452 HURRAY_SHARD_FIELD_SHARD_OFFSET => Ok(U64Source::Direct(&shard(desc)?.shard_offset)),
453 _ => Err(HURRAY_ERR_FIELD_NOT_APPLICABLE),
454 }
455}