metrale_circuit/
precision.rs1use serde::Deserialize;
19
20use crate::format::{Format, FormatError};
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct LinearFormats {
25 pub weight: Format,
27 pub activation: Format,
29}
30
31pub trait EdgePrecision {
34 fn linear(&self, module: &str) -> LinearFormats;
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
40pub enum PrecisionError {
41 #[error("precision table: {0}")]
43 Parse(String),
44 #[error("precision table entry `{pattern}`: {source}")]
46 Format {
47 pattern: String,
49 source: FormatError,
51 },
52 #[error("precision table must end with a catch-all `match = \"*\"` entry")]
54 NoCatchAll,
55}
56
57#[derive(Deserialize)]
58#[serde(deny_unknown_fields)]
59struct TableFile {
60 schema: u32,
61 checkpoint: String,
62 tier: String,
63 linear: Vec<EntryFile>,
64}
65
66#[derive(Deserialize)]
67#[serde(deny_unknown_fields)]
68struct EntryFile {
69 #[serde(rename = "match")]
70 pattern: String,
71 weight: String,
72 activation: String,
73}
74
75#[derive(Debug, Clone, PartialEq, Eq)]
77pub struct PrecisionTable {
78 pub checkpoint: String,
80 pub tier: String,
82 entries: Vec<(String, LinearFormats)>,
83 catch_all: LinearFormats,
84}
85
86impl PrecisionTable {
87 pub fn parse(text: &str) -> Result<Self, PrecisionError> {
89 let file: TableFile =
90 toml::from_str(text).map_err(|e| PrecisionError::Parse(e.to_string()))?;
91 if file.schema != 1 {
92 return Err(PrecisionError::Parse(format!(
93 "schema {} (this build reads 1)",
94 file.schema
95 )));
96 }
97 let mut entries = Vec::with_capacity(file.linear.len());
98 for e in file.linear {
99 let fmt = |s: &str| {
100 Format::parse(s).map_err(|source| PrecisionError::Format {
101 pattern: e.pattern.clone(),
102 source,
103 })
104 };
105 let formats = LinearFormats {
106 weight: fmt(&e.weight)?,
107 activation: fmt(&e.activation)?,
108 };
109 entries.push((e.pattern, formats));
110 }
111 let catch_all = match entries.pop() {
112 Some((p, f)) if p == "*" => f,
113 _ => return Err(PrecisionError::NoCatchAll),
114 };
115 Ok(PrecisionTable {
116 checkpoint: file.checkpoint,
117 tier: file.tier,
118 entries,
119 catch_all,
120 })
121 }
122}
123
124impl EdgePrecision for PrecisionTable {
125 fn linear(&self, module: &str) -> LinearFormats {
126 self.entries
127 .iter()
128 .find(|(p, _)| glob(p, module))
129 .map_or(self.catch_all, |(_, f)| *f)
130 }
131}
132
133pub(crate) fn expert_container(module: &str) -> Option<&str> {
138 let at = module.rfind(".experts.")?;
139 let rest = &module[at + ".experts.".len()..];
140 let (index, proj) = rest.split_once('.')?;
141 (!index.is_empty() && index.bytes().all(|b| b.is_ascii_digit()) && !proj.is_empty())
142 .then(|| &module[..at + ".experts".len()])
143}
144
145pub(crate) fn glob(pattern: &str, text: &str) -> bool {
147 let parts: Vec<&str> = pattern.split('*').collect();
148 if parts.len() == 1 {
149 return pattern == text;
150 }
151 let (first, last) = (parts[0], parts[parts.len() - 1]);
152 if !text.starts_with(first) || text.len() < first.len() + last.len() || !text.ends_with(last) {
153 return false;
154 }
155 let mut rest = &text[first.len()..text.len() - last.len()];
156 for mid in &parts[1..parts.len() - 1] {
157 match rest.find(mid) {
158 Some(at) => rest = &rest[at + mid.len()..],
159 None => return false,
160 }
161 }
162 true
163}
164
165#[cfg(test)]
166#[path = "precision_tests.rs"]
167mod precision_tests;