Skip to main content

entrenar/ecosystem/realizar/
quantization.rs

1//! Quantization types for GGUF export.
2
3use serde::{Deserialize, Serialize};
4
5/// Quantization type for GGUF export.
6///
7/// These correspond to llama.cpp quantization types.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9pub enum QuantizationType {
10    /// 4-bit quantization with k-quants (recommended for most use cases)
11    Q4KM,
12    /// 5-bit quantization with k-quants (higher quality than Q4_K_M)
13    Q5KM,
14    /// 8-bit quantization (highest quality, larger size)
15    Q80,
16    /// 16-bit floating point (no quantization)
17    F16,
18    /// 32-bit floating point (no quantization, largest)
19    F32,
20    /// 2-bit quantization (extreme compression, quality loss)
21    Q2K,
22    /// 3-bit quantization (aggressive compression)
23    Q3KM,
24    /// 6-bit quantization (high quality)
25    Q6K,
26}
27
28impl QuantizationType {
29    /// Get the GGUF type string.
30    pub fn as_str(&self) -> &'static str {
31        match self {
32            Self::Q4KM => "Q4_K_M",
33            Self::Q5KM => "Q5_K_M",
34            Self::Q80 => "Q8_0",
35            Self::F16 => "F16",
36            Self::F32 => "F32",
37            Self::Q2K => "Q2_K",
38            Self::Q3KM => "Q3_K_M",
39            Self::Q6K => "Q6_K",
40        }
41    }
42
43    /// Get estimated bits per weight.
44    pub fn bits_per_weight(&self) -> f32 {
45        match self {
46            Self::Q2K => 2.5,
47            Self::Q3KM => 3.5,
48            Self::Q4KM => 4.5,
49            Self::Q5KM => 5.5,
50            Self::Q6K => 6.5,
51            Self::Q80 => 8.0,
52            Self::F16 => 16.0,
53            Self::F32 => 32.0,
54        }
55    }
56
57    /// Get relative quality score (0-100).
58    pub fn quality_score(&self) -> u8 {
59        match self {
60            Self::Q2K => 50,
61            Self::Q3KM => 65,
62            Self::Q4KM => 78,
63            Self::Q5KM => 85,
64            Self::Q6K => 92,
65            Self::Q80 => 97,
66            Self::F16 => 100,
67            Self::F32 => 100,
68        }
69    }
70
71    /// Estimate output size given input size in bytes.
72    pub fn estimate_size(&self, original_bytes: u64) -> u64 {
73        let ratio = self.bits_per_weight() / 32.0;
74        (original_bytes as f32 * ratio) as u64
75    }
76
77    /// Parse from string (case-insensitive).
78    pub fn parse(s: &str) -> Option<Self> {
79        let normalized = s.to_uppercase().replace(['-', '_'], "");
80        match normalized.as_str() {
81            "Q4KM" | "Q4K" => Some(Self::Q4KM),
82            "Q5KM" | "Q5K" => Some(Self::Q5KM),
83            "Q80" | "Q8" => Some(Self::Q80),
84            "F16" | "FP16" => Some(Self::F16),
85            "F32" | "FP32" => Some(Self::F32),
86            "Q2K" | "Q2" => Some(Self::Q2K),
87            "Q3KM" | "Q3K" => Some(Self::Q3KM),
88            "Q6K" | "Q6" => Some(Self::Q6K),
89            _ => None,
90        }
91    }
92}
93
94impl std::fmt::Display for QuantizationType {
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        write!(f, "{}", self.as_str())
97    }
98}